1

Is there some way to perform a controlled interleave of vectors in R? That is, suppose I have multiple vectors v1, v2, v3 containing values and a vector of positions, something like this:

v1 <- c("a", "b", "c", "d")
v2 <- c("1", "2", "3", "4", "5")
v3 <- c("x", "y", "z")
pos <- c(1, 1, 2, 3, 2, 2, 3, 2, 1, 3, 2, 1)

It is always the case that the number of 1s in pos is equal to the number of elements in v1 and so on, i.e. all.equal(c(length(v1), length(v2), length(v3)), as.vector(table(pos))) is TRUE.

What I'd like is some way to interleave the vectors according to the values in pos, i.e. create a vector i <- c(v1[1], v1[2], v2[1], v3[1], v2[2], v2[3], v3[2], v2[4], v1[3], v3[3], v2[5], v1[4]) where the entry corresponding to the n-th appearance of 1 in pos is the n-th element of v1, and likewise for v2, v3, ...

I've tried to hack it together with a for loop, like so:

v <- list(v1, v2, v3)
for (p in 1:length(pos)) {
    ind <- pos[1:p] == pos[p]
    i[p] <- v[[pos[p]]][cumsum(ind)[p]]
}
i
#> [1] "a" "b" "1" "x" "2" "3" "y" "4" "c" "z" "5" "d"

But while this seems to get the job done, it's an awfully messy solution, and I'm hoping there's something a bit more elegant and time efficient for my real situation where pos has millions of entries.

Empiromancer
  • 3,778
  • 1
  • 22
  • 53

1 Answers1

6

Instead of iterating over positions, you can iterate over vectors:

i = character(length(pos))
for (p in 1:length(v)) i[ pos == p ] <- v[[p]]
#  "a" "b" "1" "x" "2" "3" "y" "4" "c" "z" "5" "d"

The loop can also be avoided here:

i = character(length(pos))
i[ order(pos) ] <- c(v1,v2,v3)
# "a" "b" "1" "x" "2" "3" "y" "4" "c" "z" "5" "d"

For reference, I looked at this other nice question on interleaving.

Community
  • 1
  • 1
Frank
  • 66,179
  • 8
  • 96
  • 180