“Reduce”会将未经请求的属性添加到结果中

时间:2013-12-30 16:21:00

标签: r functional-programming

对比以下两个代码段:

1

> a <- cbind(1,2)
> a
     [,1] [,2]
[1,]    1    2
> str(a)
 num [1, 1:2] 1 2

2

> b <- Reduce(cbind, list(1,2))
> b
     init  
[1,]    1 2
> str(b)
 num [1, 1:2] 1 2
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:2] "init" ""

根据Reduce帮助页面,我希望ab相同,但它们显然不完全相同。为什么?

2 个答案:

答案 0 :(得分:5)

这是因为Reduce调用f的方式以及cbind如何创建列名。 Reduce根据initright args的值确定初始值,并将该值存储在名为init的对象中,它也会反复更新。< / p>

在您的示例中,Reduce中的以下代码是发生差异的地方:

init <- x[[1L]]
ind <- ind[-1L]
for (i in ind) init <- f(init, x[[i]])

默认的cbind参数deparse.level = 1表示它尝试通过删除传递给它的对象名称来创建dimnames(如果它们生成合理的名称)。如果您希望Reduce输出与在单个号码上调用cbind相同,请设置deparse.level=0

> str(Reduce(function(x,y) cbind(x,y,deparse.level=0), list(1,2)))
 num [1, 1:2] 1 2

顺便说一下,在for循环中调用cbind是一个坏主意,因为它必须在每次迭代时重新分配内存,导致代码非常慢。分配您期望的完整输出对象(如果可以)然后填写元素会好得多。

答案 1 :(得分:3)

约书亚的答案解释了为什么你有所不同。我只是展示如何获得相同的输出。实际上,您应该将init参数初始化为NULL:

 identical(Reduce(cbind, list(1,2),init=NULL),
           cbind(1,2))
 TRUE

除此之外,调用更有效:

 do.call(cbind,list(1,2))