80

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,696
  • 3
  • 33
  • 46
Wicelo
  • 2,358
  • 2
  • 28
  • 44

6 Answers6

125

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 

Explanation

This works because R stores arrays in column-major order.

When you rbind() the two vectors, you get:

rbind_result <- rbind(a, b)
rbind_result
#   [,1] [,2] [,3]
# a    1    2    3
# b   11   12   13

Then c() coerces rbind_result into a column-wise flattened vector:

merged <- c(rbind_result)
merged
# [1] 1 11 2 12 3 13
Captain Hat
  • 2,444
  • 1
  • 14
  • 31
jalapic
  • 13,792
  • 8
  • 57
  • 87
  • 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
  • 1
    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
  • 1
    @ColorStatistics I added an edit to explain the intuition for this solution. `rbind()` does a row-wise combination of the two vectors into a matrix. Then `c()` converts the matrix into an atomic vector in column-wise order. – Jacob Bumgarner Dec 01 '22 at 23:19
  • Wonderful! as.vector() also works fine. – kurtkim Jun 29 '23 at 06:55
27

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
  • 97,041
  • 11
  • 181
  • 245
  • 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)] <- a x[c(FALSE, TRUE)] <- b Can you explain at all? – 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
  • `c(sapply(seq_along(a), function(i) c(a[i], b[i])))` seems to work – Julien Jul 31 '22 at 15:39
17

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
  • 2,074
  • 2
  • 17
  • 31
  • 11
    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
  • 3,222
  • 4
  • 28
  • 35
2

A tidyverse approach is vctrs::vec_interleave:

vctrs::vec_interleave(a, b)
#[1]  1 11  2 12  3 13
Maël
  • 45,206
  • 3
  • 29
  • 67
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)
Moritz Schauer
  • 1,378
  • 9
  • 19