0

We all know that appending a vector to a vector within a for loop in R is a bad thing because it costs time. A solution would be to do it in a vectorized style. Here is a nice example by Joshua Ulrich. It is important to first create a vector with known length and then fill it up, instead of appending each new piece to an existing piece within the loop.

Still, in his example he demonstrates 'only' how to append one data piece at a time. I am now fighting with the idea to fill a vector with vectors - not scalars.

Imagine I have a vector with a length of 100

vector <- numeric(length=100)

and a smaller vector that would fit 10 times into the first vector

vec <- seq(1,10,1)

How would I have to construct a loop that adds the smaller vector to the large vector without using c() or append ?

EDIT: This example is simplified - vec does not always consist of the same sequence but is generated within a for loop and should be added to vector.

Community
  • 1
  • 1
Jens
  • 2,363
  • 3
  • 28
  • 44
  • What do you mean by *adds the smaller vector to the large vector* ? How would your desired out put will look like? In other words, are you looking for `vector + vec` or maybe `paste0(vector, vec)`? It's not very clear as it stands. – David Arenburg Mar 11 '15 at 21:51
  • Sorry for beeing unclear with the question. In principle i look for a repeated c (vector, vec). – Jens Mar 11 '15 at 21:57

2 Answers2

3

You could just use normal vector indexing within the loop to accomplish this:

vector <- numeric(length=100)
for (i in 1:10) {
  vector[(10*i-9):(10*i)] <- 1:10
}
all.equal(vector, rep(1:10, 10))
# [1] TRUE

Of course if you were just trying to repeat a vector a certain number of times rep(vec, 10) would be the preferred solution.

josliber
  • 43,891
  • 12
  • 98
  • 133
2

A similar approach, perhaps a little more clear if your new vectors are of variable length:

# Let's over-allocate so that we now the big vector is big enough
big_vec = numeric(1e4)

this.index = 1

for (i in 1:10) {
    # Generate a new vector of random length
    new_vec = runif(sample(1:20, size = 1))
    # Stick in in big_vec by index
    big_vec[this.index:(this.index + length(new_vec) - 1)] = new_vec
    # update the starting index
    this.index = this.index + length(new_vec)
}

# truncate to only include the added values   
big_vec = big_vec[1:(this.index - 1)]

As @josilber suggested in comments, lists would be more R-ish. This is a much cleaner approach, unless the new vector generation depends on the previous vectors, in which case the for loop might be necessary.

vec_list = list()
for (i in 1:10) {
    # Generate a new vector of random length
    vec_list[[i]] = runif(sample(1:20, size = 1))
}

# Or, use lapply
vec_list = lapply(1:10, FUN = function(x) {runif(sample(1:20, size = 1))})

# Then combine with do.call
do.call(c, vec_list)

# or more simply, just unlist
unlist(vec_list)
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • hmmm, your first code snippet does not contain any "i" in the loop. Where do the different 1:10 go? should "size" be = i ? – Jens Mar 12 '15 at 11:09
  • @Jens The for loop is a counter to say "do these commands 10 times". Since I'm doing the same thing every time, and keeping track of the vector index separately, `i` doesn't need to be inside the loop. Your example had a vector `vec` always of length 10, but the vector was changing. My for loop shows a way to deal with vectors where even the length changes. The `sample` is just a way to draw a random length every time for the example. The `size` definitely should be 1, because a vector has only one length. (It's a more general method than assuming the length is always the same.) – Gregor Thomas Mar 12 '15 at 16:41
  • As a very simple example of a for loop not using `i`, `for(i in 1:5) print("Hello")` will print "Hello" 5 times. Doing the same thing every time, so we don't need `i` inside the loop. – Gregor Thomas Mar 12 '15 at 16:43
  • Wow, thanks, I was not aware of that. Learned something new, great. – Jens Mar 13 '15 at 08:09