2012-03-01 315 views
66

我有两个列表合并两个列表中的R

first = list(a = 1, b = 2, c = 3) 
second = list(a = 2, b = 3, c = 4) 

我想这样的最终产品是

$a 
[1] 1 2 

$b 
[1] 2 3 

$c 
[1] 3 4 

合并这两个列表有一个简单的函数来做到这一点?

+0

检查:http://stackoverflow.com/questions/7349608/merge-contents-within-list-of-list-by-duplicate-name – Hansi 2012-03-01 16:10:38

回答

94

如果列表中始终具有相同的结构,作为例子,那么简单的解决方案是

mapply(c, first, second, SIMPLIFY=FALSE) 
+26

这相当于'Map(c,first,second)',如果有人在意。 – Masterfool 2015-07-17 21:56:30

+2

我刚刚学习R,为什么Map(和mapply)具有'c'作为第一个参数?参数传递的参数不应该是两个列表吗? – user391339 2016-06-01 15:59:03

+2

'c'是创建列表的原始函数的名称。在R中输入c而没有尾随parens显示'function(...,recursive = FALSE).Primitive(“c”)'因此,这个陈词滥调将'c'函数映射为第一个和第二个内容。 – 2016-06-28 16:29:17

12

这里有两种选择,第一种:

both <- list(first, second) 
n <- unique(unlist(lapply(both, names))) 
names(n) <- n 
lapply(n, function(ni) unlist(lapply(both, `[[`, ni))) 

;第二,只有当它们具有相同的结构,工作原理:

apply(cbind(first, second),1,function(x) unname(unlist(x))) 

均可以得到想要的结果。

+0

我不认为你的第二个一个正常工作,因为我得到一个矩阵设计,而不是一个向量列表。 – 2012-03-01 17:16:04

+0

你是对的;如果可以的话,“apply”可以简化它。如果它不能简化,它会起作用,例如,如果'first $ c < - c(4,5)',例如。 – Aaron 2012-03-01 18:52:31

+0

第一个给我一个长度= 0的列表。名称应该被定义为某些东西? – 2017-09-26 19:44:57

23

这是萨卡的modifyList功能的一个非常简单的适应。因为它是递归的,所以它会处理比mapply更复杂的情况,它将通过忽略“第二”中不属于“第一”的项来处理不匹配的名称情况。

appendList <- function (x, val) 
{ 
    stopifnot(is.list(x), is.list(val)) 
    xnames <- names(x) 
    for (v in names(val)) { 
     x[[v]] <- if (v %in% xnames && is.list(x[[v]]) && is.list(val[[v]])) 
      appendList(x[[v]], val[[v]]) 
     else c(x[[v]], val[[v]]) 
    } 
    x 
} 

> appendList(first,second) 
$a 
[1] 1 2 

$b 
[1] 2 3 

$c 
[1] 3 4 
4

下面是一些代码,我根据@安德烈的回答写了一些代码,但没有优美/简单。其优点是,它允许一个更复杂的递归合并也不同,应与rbind连接那些刚刚与c连接的元素,且这些之间:

# Decided to move this outside the mapply, not sure this is 
# that important for speed but I imagine redefining the function 
# might be somewhat time-consuming 
mergeLists_internal <- function(o_element, n_element){ 
    if (is.list(n_element)){ 
    # Fill in non-existant element with NA elements 
    if (length(n_element) != length(o_element)){ 
     n_unique <- names(n_element)[! names(n_element) %in% names(o_element)] 
     if (length(n_unique) > 0){ 
     for (n in n_unique){ 
      if (is.matrix(n_element[[n]])){ 
      o_element[[n]] <- matrix(NA, 
            nrow=nrow(n_element[[n]]), 
            ncol=ncol(n_element[[n]])) 
      }else{ 
      o_element[[n]] <- rep(NA, 
            times=length(n_element[[n]])) 
      } 
     } 
     } 

     o_unique <- names(o_element)[! names(o_element) %in% names(n_element)] 
     if (length(o_unique) > 0){ 
     for (n in o_unique){ 
      if (is.matrix(n_element[[n]])){ 
      n_element[[n]] <- matrix(NA, 
            nrow=nrow(o_element[[n]]), 
            ncol=ncol(o_element[[n]])) 
      }else{ 
      n_element[[n]] <- rep(NA, 
            times=length(o_element[[n]])) 
      } 
     } 
     } 
    } 

    # Now merge the two lists 
    return(mergeLists(o_element, 
         n_element)) 

    } 
    if(length(n_element)>1){ 
    new_cols <- ifelse(is.matrix(n_element), ncol(n_element), length(n_element)) 
    old_cols <- ifelse(is.matrix(o_element), ncol(o_element), length(o_element)) 
    if (new_cols != old_cols) 
     stop("Your length doesn't match on the elements,", 
      " new element (", new_cols , ") !=", 
      " old element (", old_cols , ")") 
    } 

    return(rbind(o_element, 
       n_element, 
       deparse.level=0)) 
    return(c(o_element, 
      n_element)) 
} 
mergeLists <- function(old, new){ 
    if (is.null(old)) 
    return (new) 

    m <- mapply(mergeLists_internal, old, new, SIMPLIFY=FALSE) 
    return(m) 
} 

这里是我的例子:

v1 <- list("a"=c(1,2), b="test 1", sublist=list(one=20:21, two=21:22)) 
v2 <- list("a"=c(3,4), b="test 2", sublist=list(one=10:11, two=11:12, three=1:2)) 
mergeLists(v1, v2) 

这结果:

$a 
    [,1] [,2] 
[1,] 1 2 
[2,] 3 4 

$b 
[1] "test 1" "test 2" 

$sublist 
$sublist$one 
    [,1] [,2] 
[1,] 20 21 
[2,] 10 11 

$sublist$two 
    [,1] [,2] 
[1,] 21 22 
[2,] 11 12 

$sublist$three 
    [,1] [,2] 
[1,] NA NA 
[2,] 1 2 

是啊,我知道 - 也许不是最合乎逻辑的合并,但我有一个复杂的并行循环,我公顷d,以产生更多自定义功能.combine,所以我写了这个怪物:-)

1

在可能一般的,

merge_list <- function(...) by(v<-unlist(c(...)),names(v),base::c) 

注意,by()液返回attribute d列表,因此它会打印不同,但仍然是一个列表。但你可以用attr(x,"_attribute.name_")<-NULL摆脱属性。你也可以使用aggregate()

3

list3 <- append(list1, list2)还将努力