69

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 ?

igauravsehrawat
  • 3,366
  • 1
  • 31
  • 46
Wicelo
  • 2,180
  • 2
  • 27
  • 40

5 Answers5

106

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 
jalapic
  • 12,858
  • 8
  • 53
  • 80
  • 3
    This solution would not work for vector that differ in length, solution by @RichardScriven is more robust for such situations (if `length(a)` is greater than `lenght(b)` or `max` of lengths is used for indexing). – Tim Nov 02 '15 at 08:57
  • This 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. – ColorStatistics Aug 07 '20 at 22:59
  • One of the side-effects of the function `c` is that is turns data structures into vectors. So using `c` here is akin to doing `as.vector(rbind(a,b))` – jalapic Jul 27 '21 at 14:29
24

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
Rich Scriven
  • 93,629
  • 10
  • 165
  • 233
  • I 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)] – Patrick Williams Jan 31 '17 at 15:38
  • 2
    @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 hand `c(FALSE TRUE)` takes every other value starting with the **second** in the same manner. – Rich Scriven Jan 31 '17 at 18:54
12

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 in a and b.
  • seq_along(a)*2 - 1 creates a vector of the first length(a) odd numbers.
  • seq_along(b)*2 creates a vector of the first length(b) even numbers.
  • order(...) will return the indexes of the numbers in the two seq_along vectors such that x[order(x)] is an ordered list. Since the first seq_along contains the even numbers and the second seq_along has the odds, order will take the first element from the first seq_along, then the first elements of the second seq_along, then the second element from the first seq_along, etc. interspersing the two vector indexes and leaving the extra data at the tail.
  • By indexing c(a, b) using the order vector, we will intersperse a and b.

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.

Barker
  • 1,974
  • 2
  • 17
  • 31
  • 9
    Just `c(a,b)[order(c(seq_along(a),seq_along(b)))]` should do it I think. No need for the odd/even calculations. – thelatemail Jul 27 '17 at 09:17
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

mpettis
  • 2,730
  • 4
  • 24
  • 32
1

@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)
mschauer
  • 1,359
  • 8
  • 18