Interleave lists in R
Asked Answered
M

5

36

Let's say that I have two lists in R, not necessarily of equal length, like:

 a <- list('a.1','a.2', 'a.3')
 b <- list('b.1','b.2', 'b.3', 'b.4')

What is the best way to construct a list of interleaved elements where, once the element of the shorter list had been added, the remaining elements of the longer list are append at the end?, like:

interleaved <- list('a.1','b.1','a.2', 'b.2', 'a.3', 'b.3','b.4')

without using a loop. I know that mapply works for the case where both lists have equal length.

Mcewen answered 8/5, 2013 at 14:26 Comment(0)
A
43

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]
Albertson answered 8/5, 2013 at 15:0 Comment(4)
I think with the edit, the only requirement now is that the shorter list must be a and the longer list must be b, but that's easy enough the check.Fashion
I think I was just interpreting the OP's statements more strictly. "remaining elements of the longer list are append at the end" only really makes sense to me if you start the interleaving with the first element of the shorter list, and so on.Fashion
Should the output not be a list?Ligon
@Albertson Foregoing the unlist and just using c(a,b)[idx] is probably better since in general the items complex objects that get destroyed by unlist.Ligon
P
33

While investigating a similar question, I came across this beautiful solution by Gabor Grothendieck (i.e. @GGrothendieck?) for certain cases:

c(rbind(a,b))

This works equally well when a and b are both lists, or when a and b are both vectors. It's not a precise solution to OP's question, because when a and b have different lengths, it will recycle the elements of the shorter sequence, printing a warning. However, since this solution is simple and elegant, and provides an answer to a very similar question--a question of some people (like me) who find their way to this page as a result--it seemed worth adding as an answer.

Plantain answered 23/11, 2015 at 22:33 Comment(2)
I was looking into forming XML out of data.frame as plain string without much dependencies. This is the most concise approach for opening/closing tags while processing a row (with apply)! I wrapped rbind (without c) into paste & collapse="".Bott
This doesn't seem to work with dates, by some reason. It gets turned out as a list of integers.Kraul
F
5

Here's one option using the interleave function from ggplot2. I'm sure this can be improved upon, but it's a start:

require(ggplot2)
Interleave <- function(x,y){
    v <- list(x,y)
    lengths <- sapply(v,length)
    mn <- min(lengths)
    v <- v[order(lengths)]
    c(ggplot2:::interleave(v[[1]],v[[2]][seq_len(mn)]),v[[2]][(mn+1):length(v[[2]])])
}

Interleave(a,b)
Interleave(b,a)

In particular, this will do weird things if the lists are actually the same length. Perhaps someone will chime in with a better way to do the indexing for v[[2]] in the last line that avoids that degenerate case.

Fashion answered 8/5, 2013 at 14:59 Comment(0)
S
5
interleave(a, b)

# unlist(interleave(a, b))
# [1] "a.1" "b.1" "a.2" "b.2" "a.3" "b.3" "b.4"


interleave <- function(a, b) { 

  shorter <- if (length(a) < length(b)) a else b
  longer  <- if (length(a) >= length(b)) a else b

  slen <- length(shorter)
  llen <- length(longer)


  index.short <- (1:slen) + llen
  names(index.short) <- (1:slen)

  lindex <- (1:llen) + slen
  names(lindex) <- 1:llen


  sindex <- 1:slen
  names(sindex) <- 1:slen

  index <- c(sindex, lindex)
  index <- index[order(names(index))]

  return(c(a, b)[index])

}
Subsistence answered 8/5, 2013 at 15:2 Comment(0)
W
2
a <- list('a.1','a.2', 'a.3')
b <- list('b.1','b.2', 'b.3', 'b.4')

interleave <- function(a, b) {
  mlab <- min(length(a), length(b)) 
  seqmlab <- seq_len(mlab) 
  c(rbind(a[seqmlab], b[seqmlab]), a[-seqmlab], b[-seqmlab]) 
}

interleave(a, b) 

From http://r.789695.n4.nabble.com/Interleaving-elements-of-two-vectors-tp795123p1691409.html

This is a little bit faster than @Arun:

enter image description here

Wrathful answered 11/5, 2019 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.