accumulate()
按顺序将 2 参数函数应用于向量的元素。该函数的每个应用程序都使用前一个应用程序的初始值或结果作为第一个参数。第二个参数是向量的下一个值。每个应用程序的结果都以列表形式返回。在处理整个向量之前,累加可以选择性地终止,以响应累加函数返回的 done()
信号。
与 accumulate()
相比,reduce()
以相同的方式应用 2 参数函数,但丢弃除最终函数应用之外的所有结果。
accumulate2()
按顺序将函数应用于两个列表 .x
和 .y
的元素。
用法
accumulate(
.x,
.f,
...,
.init,
.dir = c("forward", "backward"),
.simplify = NA,
.ptype = NULL
)
accumulate2(.x, .y, .f, ..., .init, .simplify = NA, .ptype = NULL)
参数
- .x
-
列表或原子向量。
- .f
-
对于
accumulate()
.f
是 2 参数函数。该函数将传递累积结果或初始值作为第一个参数。序列中的下一个值作为第二个参数传递。对于
accumulate2()
,一个 3 参数函数。该函数将把累积结果作为第一个参数传递。.x
中的下一个值将作为第二个参数传递。.y
中的下一个值将作为第三个参数传递。如果
.f
返回包含在done()
中的值,则累加会提前终止。 - ...
-
传递给映射函数的附加参数。
我们现在通常建议不要使用
...
将附加(常量)参数传递给.f
。相反,使用简写匿名函数:# Instead of x |> map(f, 1, 2, collapse = ",") # do: x |> map(\(x) f(x, 1, 2, collapse = ","))
这使得更容易理解哪些参数属于哪个函数,并且往往会产生更好的错误消息。
- .init
-
如果提供,将用作开始累加的第一个值,而不是使用
.x[[1]]
。如果您想确保reduce
在.x
为空时返回正确的值,这非常有用。如果丢失,并且.x
为空,将抛出错误。 - .dir
-
作为字符串的累积方向,
"forward"
(默认)或"backward"
之一。请参阅下面有关方向的部分。 - .simplify
-
如果是
NA
(默认值),则累积的结果列表会在可能的情况下简化为原子向量。如果是TRUE
,结果会被简化,如果不可能就会出错。如果FALSE
,结果不会简化,始终返回一个列表。 - .ptype
-
如果
simplify
是NA
或TRUE
,可以选择提供向量原型来强制输出类型。 - .y
-
对于
accumulate2()
.y
是该对的第二个参数。它需要比要累加的向量短 1 个元素 (.x
)。如果设置了.init
,则.y
需要比初始值和.x
的串联短一个元素。
值
与 .x
长度相同且名称与 .x
相同的向量。
如果提供 .init
,则长度扩展 1。如果 .x
有名称,则初始值的名称为 ".init"
,否则返回的向量保持未命名。
如果 .dir
是 "forward"
(默认值),则第一个元素是初始值( .init
如果提供,或 .x
的第一个元素),最后一个元素是最终减少的值。如果积累正确,则此顺序相反。
如果 .f
返回包含在 done()
中的值,则累加会提前终止。如果完成框为空,则使用最后一个值,并且结果会短一个元素(但始终包含初始值,即使在第一次迭代时终止)。
生命周期
从 rlang 0.3.0 开始,accumulate_right()
已被软弃用,取而代之的是 .dir
参数。请注意,算法略有变化:累加值传递到右侧而不是左侧,这与右归约一致。
方向
当 .f
是像 +
或 c()
这样的关联运算时,减少的方向并不重要。例如,使用二元函数 +
约简向量 1:3
会计算左侧的和 ((1 + 2) + 3)
,以及右侧的相同和 (1 + (2 + 3))
。
在其他情况下,方向对降低的值有重要影响。例如,从左侧减少 list()
向量会生成 left-leaning 嵌套列表(或树),而从右侧减少 list()
会生成 right-leaning 列表。
也可以看看
reduce()
当您只需要最终减少的值时。
例子
# With an associative operation, the final value is always the
# same, no matter the direction. You'll find it in the first element for a
# backward (left) accumulation, and in the last element for forward
# (right) one:
1:5 |> accumulate(`+`)
#> [1] 1 3 6 10 15
1:5 |> accumulate(`+`, .dir = "backward")
#> [1] 15 14 12 9 5
# The final value is always equal to the equivalent reduction:
1:5 |> reduce(`+`)
#> [1] 15
# It is easier to understand the details of the reduction with
# `paste()`.
accumulate(letters[1:5], paste, sep = ".")
#> [1] "a" "a.b" "a.b.c" "a.b.c.d" "a.b.c.d.e"
# Note how the intermediary reduced values are passed to the left
# with a left reduction, and to the right otherwise:
accumulate(letters[1:5], paste, sep = ".", .dir = "backward")
#> [1] "a.b.c.d.e" "b.c.d.e" "c.d.e" "d.e" "e"
# By ignoring the input vector (nxt), you can turn output of one step into
# the input for the next. This code takes 10 steps of a random walk:
accumulate(1:10, \(acc, nxt) acc + rnorm(1), .init = 0)
#> [1] 0.000000 1.928421 1.148285 1.729282 2.400668 2.431910 3.939412
#> [8] 3.293159 3.488425 2.557862 3.334301
# `accumulate2()` is a version of `accumulate()` that works with
# 3-argument functions and one additional vector:
paste2 <- function(acc, nxt, sep = ".") paste(acc, nxt, sep = sep)
letters[1:4] |> accumulate(paste2)
#> [1] "a" "a.b" "a.b.c" "a.b.c.d"
letters[1:4] |> accumulate2(c("-", ".", "-"), paste2)
#> [1] "a" "a-b" "a-b.c" "a-b.c-d"
# You can shortcircuit an accumulation and terminate it early by
# returning a value wrapped in a done(). In the following example
# we return early if the result-so-far, which is passed on the LHS,
# meets a condition:
paste3 <- function(out, input, sep = ".") {
if (nchar(out) > 4) {
return(done(out))
}
paste(out, input, sep = sep)
}
letters |> accumulate(paste3)
#> [1] "a" "a.b" "a.b.c" "a.b.c"
# Note how we get twice the same value in the accumulation. That's
# because we have returned it twice. To prevent this, return an empty
# done box to signal to accumulate() that it should terminate with the
# value of the last iteration:
paste3 <- function(out, input, sep = ".") {
if (nchar(out) > 4) {
return(done())
}
paste(out, input, sep = sep)
}
letters |> accumulate(paste3)
#> [1] "a" "a.b" "a.b.c"
# Here the early return branch checks the incoming inputs passed on
# the RHS:
paste4 <- function(out, input, sep = ".") {
if (input == "f") {
return(done())
}
paste(out, input, sep = sep)
}
letters |> accumulate(paste4)
#> [1] "a" "a.b" "a.b.c" "a.b.c.d" "a.b.c.d.e"
# Simulating stochastic processes with drift
if (FALSE) {
library(dplyr)
library(ggplot2)
map(1:5, \(i) rnorm(100)) |>
set_names(paste0("sim", 1:5)) |>
map(\(l) accumulate(l, \(acc, nxt) .05 + acc + nxt)) |>
map(\(x) tibble(value = x, step = 1:100)) |>
list_rbind(id = "simulation") |>
ggplot(aes(x = step, y = value)) +
geom_line(aes(color = simulation)) +
ggtitle("Simulations of a random walk with drift")
}
相关用法
- R purrr as_vector 将列表强制转换为向量
- R purrr array-coercion 强制数组列出
- R purrr auto_browse 包装一个函数,以便在出错时自动 browser()
- R purrr as_mapper 将对象转换为映射器函数
- R purrr attr_getter 创建属性 getter 函数
- R purrr imap 将函数应用于向量的每个元素及其索引
- R purrr list_transpose 转置列表
- R purrr map_if 有条件地将函数应用于向量的每个元素
- R purrr map2 映射两个输入
- R purrr pluck 安全地获取或设置嵌套数据结构深处的元素
- R purrr insistently 将函数转换为等待,然后在错误后重试
- R purrr map_depth 在给定深度映射/修改元素
- R purrr list_simplify 将列表简化为原子或 S3 向量
- R purrr rerun 多次重新运行表达式
- R purrr quietly 包装一个函数来捕获副作用
- R purrr list_flatten 压平列表
- R purrr pmap 同时映射多个输入(“并行”)
- R purrr possibly 包装函数以返回值而不是错误
- R purrr head_while 查找全部满足谓词的头/尾。
- R purrr rbernoulli 从伯努利分布生成随机样本
- R purrr rate-helpers 创建延迟率设置
- R purrr keep_at 根据元素的名称/位置保留/丢弃元素
- R purrr keep 根据元素的值保留/丢弃元素
- R purrr transpose 转置列表。
- R purrr flatten 将列表的列表展平为简单的向量
注:本文由纯净天空筛选整理自Hadley Wickham等大神的英文原创作品 Accumulate intermediate results of a vector reduction。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。