在 R 中合并两个列表

Posted

技术标签:

【中文标题】在 R 中合并两个列表【英文标题】:Merge Two Lists in R 【发布时间】:2012-03-20 03:27:57 【问题描述】:

我有两个列表

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

是否有一个简单的功能来做到这一点?

【问题讨论】:

检查:***.com/questions/7349608/… 检查***.com/questions/59992657/… 【参考方案1】:

这里有两个选项,第一个:

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

两者都给出了预期的结果。

【讨论】:

我不认为你的第二个工作正常,因为我得到的是矩阵设计而不是向量列表。 你是对的; apply 尽可能简化它。如果不能简化它确实可以工作,例如 first$c &lt;- c(4,5) 第一个给了我一个长度=0的列表。名称应该被定义为某种东西吗? 你的列表有名字吗?【参考方案2】:

如果列表始终具有与示例中相同的结构,则更简单的解决方案是

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

【讨论】:

这相当于Map(c, first, second),如果有人关心的话。 我刚学R,为什么Map(和mapply)的第一个参数是'c'?传入的参数不应该只是两个列表吗? 'c' 是创建列表的原始函数的名称。在 R 中键入不带尾括号的 c 会显示 'function (..., recursive = FALSE) .Primitive("c")' 所以这个陈词滥调是将 'c' 函数映射到 first 和 second 的内容。 @Masterfool mapply() 更有效,因为Map() 包含mapply() 我们需要多担心以下 mapply 警告:“更长的参数不是更短长度的倍数”【参考方案3】:

这是 Sarkar 对 modifyList 函数的一个非常简单的改编。因为它是递归的,所以它会处理比mapply 更复杂的情况,并且它会通过忽略“second”中不在“first”中的项目来处理名称不匹配的情况。

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

【讨论】:

这是帮助我完成更复杂列表的一个。其他选项似乎没有处理其他元素下的元素。 是的。 IIRC 这是我欣赏并试图给予适当信任的 Sarkar 原作的美丽。【参考方案4】:

这是我最终根据@Andrei 的回答编写的一些代码,但没有优雅/简洁。优点是它允许更复杂的递归合并,并且在应该与 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

是的,我知道 - 也许不是最合乎逻辑的合并,但我有一个复杂的并行循环,我必须为它生成一个更自定义的 .combine 函数,因此我写了这个怪物:-)

【讨论】:

【参考方案5】:

一般来说可以,

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

请注意,by() 解决方案返回一个 attributed 列表,因此它会以不同的方式打印,但仍然是一个列表。但是你可以用attr(x,"_attribute.name_")&lt;-NULL 去掉这些属性。你也可以使用aggregate()

【讨论】:

【参考方案6】:
merged = map(names(first), ~c(first[[.x]], second[[.x]])
merged = set_names(merged, names(first))

使用咕噜声。也解决了你的列表不整齐的问题。

【讨论】:

【参考方案7】:

在@Aaron 离开堆栈溢出和@Theo 回答之后,合并列表的元素采用向量c 的形式。 但如果你想绑定行和列,请使用rbindcbind

merged = map(names(first), ~rbind(first[[.x]], second[[.x]])
merged = set_names(merged, names(first))

【讨论】:

【参考方案8】:

使用 dplyr,我发现这一行适用于使用相同名称的命名列表:

as.list(bind_rows(first, second))

【讨论】:

以上是关于在 R 中合并两个列表的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中把两个列表的各项分别合并为列表

如何在 Nix 中合并两个列表?

在python中合并两个列表的最快方法是啥?

在 R 中合并两个数据帧,没有重复的条目

在 Haskell 中合并两个列表

以基因名字合并两个数据集(R语言,merge函数)