10.6 归约累计函数

reduce、accumulate()函数用法介绍.

10.6.1 reduce 函数

reduce() 将多个元素的值组合(由函数驱动)成一个,组合的动词(函数)由参数.f决定。

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

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

如下,将 1 到 100 共 100 个元素由函数+组合成一个元素,即将 100 个数字连续相加:

reduce(1:100,`+`)
#> [1] 5050

连续相减

reduce(5:1,`-`)
#> [1] -5
 # 等同于
5-4-3-2-1
#> [1] -5

.dir 参数决定动词(函数)方向:

str(reduce(1:4, list))
#> List of 2
#>  $ :List of 2
#>   ..$ :List of 2
#>   .. ..$ : int 1
#>   .. ..$ : int 2
#>   ..$ : int 3
#>  $ : int 4
# 等同
# list(list(list(list(1),2),3),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
# 等同 
# list(1,list(2,list(3,list(4))))

自己试着比较添加 .dir 参数后的差异。

在实际工作中,我常用reduce函数实现连续merge()left_joind()等功能,如下所示:

n <- 10
dt1 <- data.frame(a=letters[n],b1=rnorm(n))
dt2 <- data.frame(a=letters[n],b2=rnorm(n))
dt3 <- data.frame(a=letters[n],b3=rnorm(n))
dt4 <- data.frame(a=letters[n],b4=rnorm(n))

reduce(list(dt1,dt2,dt3,dt4),merge) %>% 
  head()
#>   a     b1     b2   b3      b4
#> 1 j -0.387 -0.209 2.04 -1.1462
#> 2 j -0.387 -0.209 2.04  0.8462
#> 3 j -0.387 -0.209 2.04  0.0817
#> 4 j -0.387 -0.209 2.04 -1.3051
#> 5 j -0.387 -0.209 2.04 -0.9449
#> 6 j -0.387 -0.209 2.04  0.4543
# not run
# reduce(list(dt1,dt2,dt3,dt4),merge,by='a') same above

关于reduce2()函数,第二个元素需要比第一个元素长度少一个,如下所示:

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"

10.6.2 accumulate 函数

accumulate()reduce()的区别是accumulate()记录过程结果,而reduce()`仅保持最后结果。

1:5 %>% accumulate(`+`)
#> [1]  1  3  6 10 15
1:5 %>% accumulate(`+`, .dir = "backward")
#> [1] 15 14 12  9  5
accumulate(letters[1:5], paste, sep = ".")
#> [1] "a"         "a.b"       "a.b.c"     "a.b.c.d"   "a.b.c.d.e"
paste2 <- function(x, y, sep = ".") paste(x, y, 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]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "a-b"
#> 
#> [[3]]
#> [1] "a-b.c"
#> 
#> [[4]]
#> [1] "a-b.c-d"