Interleaving vectors and matrices (part 1)

Interleaving 2 vectors - simplest solution

I have 2 vectors of equal length that I want to interleave

  • First input: 1, 2, 3
  • Second input: 4, 5, 6
  • Desired output: 1, 4, 2, 5, 3, 6

The simplest base R solution is to rbind() the 2 inputs and then unravel the matrix.

And when I say “simplest” solution, I mean “thing that is shortest but totally non-obvious”.

v1 <- c(1L, 2L, 3L)
v2 <- c(4L, 5L, 6L)

c(rbind(v1, v2))
[1] 1 4 2 5 3 6

Interleaving 2 vectors - faster solution

Both rbind and c copy the data, and copying takes time.

Rather than using c() to turn the matrix into a vector, you could also just unset the dim attribute on the matrix. This will give the same result, but avoid doing any memory allocation associated with the c call.

res <- rbind(v1, v2)
attributes(res) <- NULL
res
[1] 1 4 2 5 3 6
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Large-ish example
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
v1 <- v2 <- integer(10000)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Benchmark
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bench_res <- bench::mark(
  c(rbind(v1, v2)),
  `remove dims` = {
    res <- rbind(v1, v2)
    attributes(res) <- NULL
    res
  }
)
Table 1: bench::mark() comparing interleaving methods. Removing attributes saves on memory allocation and is therefore much faster than c()
expression median itr/sec mem_alloc
c(rbind(v1, v2)) 129.2µs 7523.19 156.3KB
{
res <- rbind(v1, v2)
attributes(res) <- NULL
res
} 51.8µs 18293.02 78.2KB
Loading required namespace: tidyr

Summary

  • Don’t write a for loop to interleave two vectors of equal length.