Interlacing Two Vectors

Interlacing two vectors

You can rbind them, then coerce back to a vector.

a <- c("a1", "a2", "a3") 
b <- c("b1", "b2", "b3")
c(rbind(a,b))

# [1] "a1" "b1" "a2" "b2" "a3" "b3"

As @Moody_Mudskipper points out, as.vector(rbind(a,b))) is faster

For the case when the lengths are different, I found the following solution from Rolf Turner at this link: http://r.789695.n4.nabble.com/Interleaving-elements-of-two-vectors-td795123.html

riffle <- function (a,b) { 
n <- min(length(a),length(b))
p1 <- as.vector(rbind(a[1:n],b[1:n]))
p2 <- c(a[-(1:n)],b[-(1:n)])
c(p1,p2)
}

riffle(1:3, letters[1:5])

# [1] "1" "a" "2" "b" "3" "c" "d" "e"

Alternate, interweave or interlace two vectors

Your rbind method should work well. You could also use

rpois(lambda=c(3,4),n=1e6)

because R will automatically replicate the vector of lambda values to the required length. There's not much difference in speed:

library(rbenchmark)
benchmark(rpois(1e6,c(3,4)),
c(rbind(rpois(5e5,3),rpois(5e5,4))))

# test replications elapsed relative
# 2 c(rbind(rpois(5e+05, 3), rpois(5e+05, 4))) 100 23.390 1.112168
# 1 rpois(1e+06, c(3, 4)) 100 21.031 1.000000

and elegance is in the eye of the beholder ... of course, the c(rbind(...)) method works in general for constructing alternating vectors, while the other solution is specific to rpois or other functions that replicate their arguments in that way.

How do I interlace two Rust vectors into a new vector?

Using interleave() function or interleave() method from Itertools crate:

use itertools::{interleave, Itertools};

fn main() {
let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![4.0, 5.0, 6.0];
let v = interleave(v1, v2).collect::<Vec<_>>();
dbg!(v);

let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![4.0, 5.0, 6.0];
let v = v1
.into_iter()
.interleave(v2.into_iter())
.collect::<Vec<_>>();
dbg!(v);
}

Interweave two columns into one in r

If you wrap the c function around a matrix object (which is what df is above), it will "unwrap them in column-dominant manner (except it needs to be created with rbind so that the interleaving will occur):

c(rbind(col1,col2))
[1] 1 5 2 6 3 7 4 8

If you want it to print at the console as though it were a "column vector" in matrix parlance you could `cbind that result to get a one column matrix object:

cbind( c(rbind(col1,col2)) )
[,1]
[1,] 1
[2,] 5
[3,] 2
[4,] 6
[5,] 3
[6,] 7
[7,] 4
[8,] 8

Alternate, interweave or interlace two matrices

Here are two alternatives.

First, assuming we have to start with "x" and "y", you can try interleave from the "gdata" package:

library(gdata)
interleave(x, y)
# ranks names
# [1,] "1" "Karl"
# [2,] "" "Cape Town"
# [3,] "2" "Klaus"
# [4,] "" "London"
# [5,] "3" "Mary"
# [6,] "" "Berlin"

Second, assuming we can start with "ranks", "names", and "universities", you can use base R, like this:

cbind(c(t(cbind(ranks, ""))), c(t(cbind(names, universities))))
# [,1] [,2]
# [1,] "1" "Karl"
# [2,] "" "Cape Town"
# [3,] "2" "Klaus"
# [4,] "" "London"
# [5,] "3" "Mary"
# [6,] "" "Berlin"

A better alternative, however, would be to use something like melt (from "reshape2" or "data.table"). This would allow you to add another variable that indicates what type of measurement a value represents.

library(data.table)
melt(data.table(ranks, names, universities), "ranks")
# ranks variable value
# 1: 1 names Karl
# 2: 2 names Klaus
# 3: 3 names Mary
# 4: 1 universities Cape Town
# 5: 2 universities London
# 6: 3 universities Berlin

Or, to match your desired ordering:

library(data.table)
setorder(melt(data.table(ranks, names, universities), "ranks"), ranks)[]
# ranks variable value
# 1: 1 names Karl
# 2: 1 universities Cape Town
# 3: 2 names Klaus
# 4: 2 universities London
# 5: 3 names Mary
# 6: 3 universities Berlin

How to merge 2 vectors alternating indexes?

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

Packing and de-interleaving two __m256 registers

// __m256   lo = a0 b0 a1 b1 a2 b2 a3 b3 // load proximal elements
// __m256 hi = a4 b4 a5 b5 a6 b6 a7 b7
// __m256 colA = a0 a1 a2 a3 a4 a5 a6 a7 // goal
// __m256 colB = b0 b1 b2 b3 b4 b5 b6 b7

It seems we can do this shuffle even faster than my orginal answer:

void unpack_cols(__m256i lo, __m256i hi, __m256i& colA, __m256i& colB) {
const __m256i mask = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);
// group cols crossing lanes:
// a0 a1 a2 a3 b0 b1 b2 b3
// a4 a5 a6 a7 b4 b5 b6 b7
auto lo_grouped = _mm256_permutevar8x32_epi32(lo, mask);
auto hi_grouped = _mm256_permutevar8x32_epi32(hi, mask);

// swap lanes:
// a0 a1 a2 a3 a4 a5 a6 a7
// b0 b1 b2 b3 b4 b5 b6 b7
colA = _mm256_permute2x128_si256(lo_grouped, hi_grouped, 0 | (2 << 4));
colB = _mm256_permute2x128_si256(lo_grouped, hi_grouped, 1 | (3 << 4));
}

While both instructions have a 3 cycles latency on Haswell (see Agner Fog) they have a single cycle throughput. This means it has a throughput of 4 cycles and 8 cycles latency. If you have a spare register which can keep the mask this should be better. Doing only two of these in parallel allows you to completly hide its latency. See godbolt and rextester.


Old answer, kept for reference:

The fastest way to do this shuffle is the following:

void unpack_cols(__m256i lo, __m256i hi, __m256i& colA, __m256i& colB) {
// group cols within lanes:
// a0 a1 b0 b1 a2 a3 b2 b3
// a4 a5 b4 b5 a6 a7 b6 b7
auto lo_shuffled = _mm256_shuffle_epi32(lo, _MM_SHUFFLE(3, 1, 2, 0));
auto hi_shuffled = _mm256_shuffle_epi32(hi, _MM_SHUFFLE(3, 1, 2, 0));

// unpack lo + hi a 64 bit
// a0 a1 a4 a5 a2 a3 a6 a7
// b0 b1 b4 b5 b2 b3 b6 b7
auto colA_shuffled = _mm256_unpacklo_epi64(lo_shuffled, hi_shuffled);
auto colB_shuffled = _mm256_unpackhi_epi64(lo_shuffled, hi_shuffled);

// swap crossing lanes:
// a0 a1 a2 a3 a4 a5 a6 a7
// b0 b1 b2 b3 b4 b5 b6 b7
colA = _mm256_permute4x64_epi64(colA_shuffled, _MM_SHUFFLE(3, 1, 2, 0));
colB = _mm256_permute4x64_epi64(colB_shuffled, _MM_SHUFFLE(3, 1, 2, 0));
}

Starting with Haswell this has a throughput of 6 cycles (sadly six instructions on port 5). According to Agner Fog _mm256_permute4x64_epi64 has a latency of 3 cycles. This means unpack_cols has a latency of 11 8 cycles.

You can check the code on godbolt.org or test it at rextester which has AVX2 support but sadly no permalinks like godbolt.


Note that this is also very close to the problem I had where I gathered 64 bit ints and needed the high and low 32 bits separated.


Note that gather performance is really bad in Haswell but according to Agner Fog Skylake got a lot better at it (~12 cycles throughput down to ~5). Still shuffling around such simple patterns should still be a lot faster than gathering.

Interleave lists in R

Here's one way:

idx <- order(c(seq_along(a), seq_along(b)))
unlist(c(a,b))[idx]

# [1] "a.1" "b.1" "a.2" "b.2" "a.3" "b.3" "b.4"

As @James points out, since you need a list back, you should do:

(c(a,b))[idx]


Related Topics



Leave a reply



Submit