當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


R purrr reduce 通過迭代應用二元函數將列表減少為單個值


reduce() 是將向量的元素組合成單個值的運算。該組合由 .f 驅動,這是一個采用兩個值並返回單個值的二元函數:在 1:3 上減少 f 可計算值 f(f(1, 2), 3)

用法

reduce(.x, .f, ..., .init, .dir = c("forward", "backward"))

reduce2(.x, .y, .f, ..., .init)

參數

.x

列表或原子向量。

.f

對於 reduce() ,一個 2 參數函數。該函數將傳遞累積值作為第一個參數,"next" 值作為第二個參數。

對於 reduce2() ,一個 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" 之一。請參閱下麵有關方向的部分。

.y

對於 reduce2()accumulate2() ,傳遞給 .f 的附加參數。如果未設置 init,則 .y 應比 .x 短 1 個元素。

方向

.f 是像 +c() 這樣的關聯運算時,減少的方向並不重要。例如,使用二元函數 + 約簡向量 1:3 會計算左側的和 ((1 + 2) + 3),以及右側的相同和 (1 + (2 + 3))

在其他情況下,方向對降低的值有重要影響。例如,從左側減少 list() 向量會產生一個左傾嵌套列表(或樹),而從右側減少 list() 則會產生一個右傾列表。

生命周期

從 purrr 0.3.0 開始,reduce_right() 已被軟棄用。請改用reduce().dir 參數。請注意,算法已更改。 reduce_right() 計算 f(f(3, 2), 1)reduce(.dir = \"backward\") 計算 f(1, f(2, 3)) 。這是從右側減少的標準方法。

要使用與 reduce_right() 相同的歸約更新代碼,隻需反轉向量並使用左歸約:

# Before:
reduce_right(1:3, f)

# After:
reduce(rev(1:3), f)

reduce2_right() 自 purrr 0.3.0 起已被軟棄用,無需替換。目前尚不清楚在這種情況下正確的歸約應具有哪些算法屬性。如果您了解使用三元函數進行正確約簡的用例,請聯係我們。

也可以看看

accumulate() 用於返回歸約的所有中間值的版本。

例子

# Reducing `+` computes the sum of a vector while reducing `*`
# computes the product:
1:3 |> reduce(`+`)
#> [1] 6
1:10 |> reduce(`*`)
#> [1] 3628800

# 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:
reduce(1:10, \(acc, nxt) acc + rnorm(1), .init = 0)
#> [1] 5.293988

# When the operation is associative, the direction of reduction
# does not matter:
reduce(1:4, `+`)
#> [1] 10
reduce(1:4, `+`, .dir = "backward")
#> [1] 10

# However with non-associative operations, the reduced value will
# be different as a function of the direction. For instance,
# `list()` will create left-leaning lists when reducing from the
# right, and right-leaning lists otherwise:
str(reduce(1:4, list))
#> List of 2
#>  $ :List of 2
#>   ..$ :List of 2
#>   .. ..$ : int 1
#>   .. ..$ : int 2
#>   ..$ : int 3
#>  $ : int 4
str(reduce(1:4, list, .dir = "backward"))
#> List of 2
#>  $ : int 1
#>  $ :List of 2
#>   ..$ : int 2
#>   ..$ :List of 2
#>   .. ..$ : int 3
#>   .. ..$ : int 4

# reduce2() takes a ternary function and a second vector that is
# one element smaller than the first vector:
paste2 <- function(x, y, sep = ".") paste(x, y, sep = sep)
letters[1:4] |> reduce(paste2)
#> [1] "a.b.c.d"
letters[1:4] |> reduce2(c("-", ".", "-"), paste2)
#> [1] "a-b.c-d"

x <- list(c(0, 1), c(2, 3), c(4, 5))
y <- list(c(6, 7), c(8, 9))
reduce2(x, y, paste)
#> [1] "0 2 6 4 8" "1 3 7 5 9"


# You can shortcircuit a reduction 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 |> reduce(paste3)
#> [1] "a.b.c"

# Here the early return branch checks the incoming inputs passed on
# the RHS:
paste4 <- function(out, input, sep = ".") {
  if (input == "j") {
    return(done(out))
  }
  paste(out, input, sep = sep)
}
letters |> reduce(paste4)
#> [1] "a.b.c.d.e.f.g.h.i"
源代碼:R/reduce.R

相關用法


注:本文由純淨天空篩選整理自Hadley Wickham等大神的英文原創作品 Reduce a list to a single value by iteratively applying a binary function。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。