2013-05-08 35 views
25

比方说,我有两个名单中R,不一定相等的长度,如:交错名单

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

什么是构造交错元素的列表的最佳方式,其中,曾经的元素较短的列表已被添加,较长列表的其余元素被添加在末尾?,如:

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

不使用循环。我知道地图适用于两个列表具有相同长度的情况。

回答

30

这里有一种方法:

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" 

正如@詹姆斯所指出的,因为你需要一个列表回来了,你应该做的:

(c(a,b))[idx] 
+0

我认为编辑,现在唯一的要求是,较短的列表必须是a和较长的列表必须是b,但这很容易检查。 – joran 2013-05-08 15:05:10

+0

我想我只是更严格地解释OP的陈述。 “较长列表的剩余元素被添加到最后”对我来说只有真正有意义,如果你使用较短列表的第一个元素开始交织,依此类推。 – joran 2013-05-08 15:11:59

+0

输出不应该是一个列表吗? – James 2013-05-08 15:27:35

5

下面是使用interleave函数的一个选项,从ggplot2。我敢肯定,这可以改进,但它是一个开始:

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) 

特别是,这会做奇怪的事情,如果名单实际上是相同的长度。也许有人会用最好的方式编造最后一行v[[2]]的索引,以避免这种退化的情况。

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]) 

} 
21

在调查类似的问题,我来了横跨this Gabor Grothendieck的美丽解决方案(即@GGrothendieck?)在某些情况下:

c(rbind(a,b)) 

ab都是列表或ab都是矢量时,此功能同样适用。这不是OP的问题的精确解决方案,因为当ab具有不同的长度时,它将回收较短序列的元素并打印警告。然而,由于这个解决方案简单而优雅,并且为一个非常类似的问题提供了一个答案 - 这是一些人(像我这样)通过这个页面找到他们的方式的问题 - 似乎值得添加一个答案。

+0

我正在研究将data.frame中的XML形成为纯粹的字符串,而没有太多的依赖关系。这是在处理一行时使用最简洁的方式打开/关闭标签(使用apply)!我将rbind(没有c)包装到paste&collapse =“”中。 – mlt 2016-08-16 20:40:06

+0

由于某种原因,这似乎不适用于日期。它变成了一个整数列表。 – wpkzz 2017-05-03 21:10:13