How to merge 2 vectors alternating indexes?
Solution 1
This will work using rbind
:
c(rbind(a, b))
For example:
a = c(1,2,3)
b = c(11,12,13)
c(rbind(a,b))
#[1] 1 11 2 12 3 13
Solution 2
The rbind()
answer by @jalapic is excellent. Here's an alternative that creates a new vector then assigns the alternating values to it.
a <- c(1,2,3)
b <- c(11,12,13)
x <- vector(class(a), length(c(a, b)))
x[c(TRUE, FALSE)] <- a
x[c(FALSE, TRUE)] <- b
x
# [1] 1 11 2 12 3 13
And one more that shows append
c(sapply(seq_along(a), function(i) append(a[i], b[i], i)))
# [1] 1 11 2 12 3 13
Solution 3
Just wanted to add a simpler solution that works for when vectors are unequal length and you want to append the extra data to the end.
> a <- 1:3
> b <- 11:17
> c(a, b)[order(c(seq_along(a)*2 - 1, seq_along(b)*2))]
[1] 1 11 2 12 3 13 14 15 16 17
Explanation:
c(a, b)
creates a vector of the values ina
andb
.seq_along(a)*2 - 1
creates a vector of the firstlength(a)
odd numbers.seq_along(b)*2
creates a vector of the firstlength(b)
even numbers.order(...)
will return the indexes of the numbers in the twoseq_along
vectors such thatx[order(x)]
is an ordered list. Since the firstseq_along
contains the even numbers and the secondseq_along
has the odds, order will take the first element from the firstseq_along
, then the first elements of the secondseq_along
, then the second element from the firstseq_along
, etc. interspersing the two vector indexes and leaving the extra data at the tail.- By indexing
c(a, b)
using theorder
vector, we will interspersea
andb
.
As a note, since seq_along
returns numeric(0)
when the input is NULL
this solution works even if one of the vectors is length 0
.
Solution 4
I had to solve a similar problem, but my vectors were of unequal length. And, I didn't want to recycle the shorter vector, but just append the tail of the longer vector.
And the solution for @RichardScriven didn't work for me (though I may have done something wrong and didn't try hard to troubleshoot).
Here is my solution:
#' Riffle-merges two vectors, possibly of different lengths
#'
#' Takes two vectors and interleaves the elements. If one vector is longer than
#' the other, it appends on the tail of the longer vector to the output vector.
#' @param a First vector
#' @param b Second vector
#' @return Interleaved vector as described above.
#' @author Matt Pettis
riffle <- function(a, b) {
len_a <- length(a)
len_b <- length(b)
len_comm <- pmin(len_a, len_b)
len_tail <- abs(len_a - len_b)
if (len_a < 1) stop("First vector has length less than 1")
if (len_b < 1) stop("Second vector has length less than 1")
riffle_common <- c(rbind(a[1:len_comm], b[1:len_comm]))
if (len_tail == 0) return(riffle_common)
if (len_a > len_b) {
return(c(riffle_common, a[(len_comm + 1):len_a]))
} else {
return(c(riffle_common, b[(len_comm + 1):len_b]))
}
}
# Try it out
riffle(1:7, 11:13)
[1] 1 11 2 12 3 13 4 5 6 7
riffle(1:3, 11:17)
[1] 1 11 2 12 3 13 14 15 16 17
HTH, Matt
Solution 5
@MBo's answer to my question at https://stackoverflow.com/a/58773002/2556061 implies a solution for evenly interlacing vectors of unequal length. I'm reporting it here in for reference.
interleave <- function(x, y)
{
m <- length(x)
n <- length(y)
xi <- yi <- 1
len <- m + n
err <- len %/% 2
res <- vector()
for (i in 1:len)
{
err <- err - m
if (err < 0)
{
res[i] <- x[xi]
xi <- xi + 1
err <- err + len
} else
{
res[i] <- y[yi]
yi <- yi + 1
}
}
res
}
gives
interleave(1:10, 100:120)
c(100, 1, 101, 102, 2, 103, 104, 3, 105, 106, 4, 107, 108, 5, 109, 110, 111, 6, 112, 113, 7, 114, 115, 8, 116, 117, 9, 118, 119, 10, 120)
Wicelo
Updated on June 15, 2022Comments
-
Wicelo almost 2 years
I would like to merge 2 vectors this way :
a = c(1,2,3) b = c(11,12,13) merged vector : c(1,11,2,12,3,13)
How could I do it ?
-
Tim over 8 yearsThis solution would not work for vector that differ in length, solution by @RichardScriven is more robust for such situations (if
length(a)
is greater thanlenght(b)
ormax
of lengths is used for indexing). -
Patrick Williams over 7 yearsI love your answer to this question (though in the append example, when I have one vector with 2-items, and another with 3-items, I end up with a final vector with an NA at the end). I went with the first option, but don't quite understand what is going on in these lines: x[c(TRUE, FALSE)] <- a x[c(FALSE, TRUE)] <- b Can you explain at all?
-
Rich Scriven over 7 years@PatrickWilliams -
c(TRUE, FALSE)
, when used to index, means to take every other value starting with the first.c(TRUE, FALSE)
is recycled through the entire length of the vector (so it's like saying "yes, no, yes, no, yes, no" in this example). On the other handc(FALSE TRUE)
takes every other value starting with the second in the same manner. -
thelatemail almost 7 yearsJust
c(a,b)[order(c(seq_along(a),seq_along(b)))]
should do it I think. No need for the odd/even calculations. -
ColorStatistics almost 4 yearsThis is a great solution! Thank you. It would be great if you could add a brief explanation as to why it works as it is not immediately obvious why row binding 2 vectors and then concatenating the resulting vectors would produce the interspersed result. I am still trying to figure this out.
-
jalapic almost 3 yearsOne of the side-effects of the function
c
is that is turns data structures into vectors. So usingc
here is akin to doingas.vector(rbind(a,b))