简体   繁体   English

在 R 中合并两个列表

[英]Merge Two Lists in R

I have two lists我有两个列表

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

I want to merge these two lists so the final product is我想合并这两个列表,所以最终产品是

$a
[1] 1 2

$b
[1] 2 3

$c
[1] 3 4

Is there a simple function to do this?有没有简单的 function 可以做到这一点?

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

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

This is a very simple adaptation of the modifyList function by Sarkar.这是 Sarkar 对 modifyList 函数的一个非常简单的改编。 Because it is recursive, it will handle more complex situations than mapply would, and it will handle mismatched name situations by ignoring the items in 'second' that are not in 'first'.因为它是递归的,它将处理比mapply更复杂的情况,并且它将通过忽略不在 'first' 中的 'second' 中的项目来处理不匹配的名称情况。

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

Here are two options, the first:这里有两个选项,第一个:

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

and the second, which works only if they have the same structure:第二个,只有当它们具有相同的结构时才有效:

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

Both give the desired result.两者都给出了想要的结果。

Here's some code that I ended up writing, based upon @Andrei's answer but without the elegancy/simplicity.这是我最终根据@Andrei 的回答编写的一些代码,但没有优雅/简单。 The advantage is that it allows a more complex recursive merge and also differs between elements that should be connected with rbind and those that are just connected with c :优点是它允许更复杂的递归合并,并且在应该与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)
}

Here's my example:这是我的例子:

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)

This results in:这导致:

$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

Yeah, I know - perhaps not the most logical merge but I have a complex parallel loop that I had to generate a more customized .combine function for, and therefore I wrote this monster :-)是的,我知道 - 也许不是最合乎逻辑的合并,但我有一个复杂的并行循环,我必须为它生成一个更自定义的.combine函数,因此我写了这个怪物:-)

In general one could,一般来说,可以,

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

Note that the by() solution returns an attribute d list, so it will print differently, but will still be a list.请注意, by()解决方案返回一个attribute d 列表,因此它将以不同的方式打印,但仍然是一个列表。 But you can get rid of the attributes with attr(x,"_attribute.name_")<-NULL .但是您可以使用attr(x,"_attribute.name_")<-NULL去除属性。 You can probably also use aggregate() .您也可以使用aggregate()

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

Using purrr.使用 purrr。 Also solves the problem of your lists not being in order.还解决了您的列表不按顺序的问题。

We can do a lapply with c() , and use setNames to assign the original name to the output.我们可以使用c()进行lapply ,并使用setNames将原始名称分配给 output。

setNames(lapply(1:length(first), function(x) c(first[[x]], second[[x]])), names(first))

$a
[1] 1 2

$b
[1] 2 3

$c
[1] 3 4

Following @Aaron left Stack Overflow and @Theo answer, the merged list's elements are in form of vector c .在@Aaron 离开 Stack Overflow 和@Theo 回答之后,合并列表的元素采用向量c形式。 But if you want to bind rows and columns use rbind and cbind .但是如果你想绑定行和列,请使用rbindcbind

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

Using dplyr, I found that this line works for named lists using the same names:使用 dplyr,我发现这条线适用于使用相同名称的命名列表:

as.list(bind_rows(first, second)) as.list(bind_rows(第一,第二))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM