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 ?
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 ?
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
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
length(a)
is greater than lenght(b)
or max
of lengths is used for indexing). –
Mikkanen c
is that is turns data structures into vectors. So using c
here is akin to doing as.vector(rbind(a,b))
–
Ironmonger 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. –
Violent 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
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. –
Quartered c(sapply(seq_along(a), function(i) c(a[i], b[i])))
seems to work –
Analiese 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.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
.
c(a,b)[order(c(seq_along(a),seq_along(b)))]
should do it I think. No need for the odd/even calculations. –
Kieserite 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
A tidyverse
approach is vctrs::vec_interleave
:
vctrs::vec_interleave(a, b)
#[1] 1 11 2 12 3 13
@MBo's answer to my question at https://mcmap.net/q/244098/-create-boolean-vector-of-length-n-with-k-true-values-well-dispersed 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)
© 2022 - 2024 — McMap. All rights reserved.