& Ldquo; Reduce & rdquo; Adds unsaved attributes to result

advertisements

Contrast the following two code snippets:

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" ""

According to the Reduce help page, i would expect a and b to be the same, but they're obviously not quite. Why is it?


It's because of how Reduce calls f and how cbind creates column names. Reduce determines the initial value based on the values of the init and right args and stores that value in an object named init, which it also happens to update iteratively.

In your example, the following code in Reduce is where the difference occurs:

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

The default cbind argument, deparse.level = 1 means that it tries to create dimnames via deparsing the object names passed to it (if they make sensible names). If you want the Reduce output to be identical to calling cbind on single numbers, then set deparse.level=0.

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

As an aside, calling cbind in a for loop is a bad idea because it must re-allocate memory on each iteration, leading to very slow code. It's much better to allocate the full output object you expect (if you can) and then fill in the elements.