Question

Say I have two vectors v1 and v2 and that I want to call rbind(v1, v2). However, supposed length(v1) > length(v2). From the documentation I have read that the shorter vector will be recycled. Here is an example of this "recycling":

v1 <- c(1, 2, 3, 4, 8, 5, 3, 11)
v2 <- c(9, 5, 2)
rbind(v1, v2)
#    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# v1    1    2    3    4    8    5    3   11
# v2    9    5    2    9    5    2    9    5
  1. Is there any straightforward way I can stop v2 from being recycled and instead make the remaining entries 0?
  2. Is there a better way to build vectors and matrices?

All help is greatly appreciated!

Was it helpful?

Solution

use the following:

rbind(v1, v2=v2[seq(v1)])

   [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
v1    1    2    3    4    8    5    3   11
v2    9    5    2   NA   NA   NA   NA   NA

Why it works: Indexing a vector by a value larger than its length returns a value of NA at that index point.

 #eg: 
{1:3}[c(3,5,1)]
#[1]  3 NA  1

Thus, if you index the shorter one by the indecies of the longer one, you willl get all of the values of the shorter one plus a series of NA's


A generalization:

v <- list(v1, v2)
n <- max(lengths(v))
# same:
# n <- max(sapply(v, length))
do.call(rbind, lapply(v, `[`, seq_len(n)))

OTHER TIPS

Although I think Ricardo has offered a nice solution, something like this would also work applying a function to a list of the vectors you wish to bind. You could specify the character to fill with as well.

test <- list(v1,v2)
maxlen <- max(sapply(test,length))
fillchar <- 0
do.call(rbind,lapply(test, function(x) c(x, rep(fillchar, maxlen - length(x) ) )))

Or avoiding all the do.call(rbind madness:

t(sapply(test, function(x) c(x, rep(fillchar, maxlen - length(x)))))

#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#[1,]    1    2    3    4    8    5    3   11
#[2,]    9    5    2    0    0    0    0    0

In case you have many vectors to rbind finding longer and shorter vectors could be tedious. In which case this is an option:

require(plyr)

rbind.fill.matrix(t(v1), t(v2))

or,

rbind.fill(as.data.frame(t(v1)), as.data.frame(t(v2)))

Here's another option using transpose from "data.table":

library(data.table)
setDT(transpose(list(v1, v2)))[]
#    V1 V2 V3 V4 V5 V6 V7 V8
# 1:  1  2  3  4  8  5  3 11
# 2:  9  5  2 NA NA NA NA NA

transpose also has a fill argument:

setDT(transpose(list(v1, v2), fill = 0))[]
#    V1 V2 V3 V4 V5 V6 V7 V8
# 1:  1  2  3  4  8  5  3 11
# 2:  9  5  2  0  0  0  0  0

If you have many vectors named in the same pattern--for example, you have v1, v2, v3,..., v10--you can use mget:

setDT(transpose(mget(paste0("v", 1:10))))[]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top