按元素名称组合/合并列表(列表中的列表)

Posted

技术标签:

【中文标题】按元素名称组合/合并列表(列表中的列表)【英文标题】:Combine/merge lists by elements names (list in list) 【发布时间】:2014-06-22 09:37:35 【问题描述】:

我有两个列表,其元素的名称部分重叠,我需要将它们逐个元素合并/组合成一个列表:

我的问题与Combine/merge lists by elements names有关,但我的示例中的数据结构更复杂,因此上述链接下提供的解决方案在这种情况下不起作用。

这是一个简化的玩具示例:

l.1 <- list(list(c(10,20), NULL),list(c(10,20,30), NULL), list(c(9,12,13), NULL))
names(l.1) <- c("a","b","c")

l.2 <- list(list(NULL,c(1,0)),list(NULL,c(1,2,3)))
names(l.2) <- c("a","b")

因此,数据属于“列表中的列表”类型,如下所示:

# > l.1
# $a
# $a[[1]]
# [1] 10 20
# $a[[2]]
# NULL
# 
# $b
# $b[[1]]
# [1] 10 20 30
# $b[[2]]
# NULL
# 
# $c
# $c[[1]]
# [1]  9 12 13
# $c[[2]]
# NULL
# 
# > l.2
# $a
# $a[[1]]
# NULL
# $a[[2]]
# [1] 1 0
# 
# $b
# $b[[1]]
# NULL
# $b[[2]]
# [1] 1 2 3

合并两个列表的结果应如下所示:

# $a
# $a[[1]]
# [1] 10 20
# $a[[2]]
# [1] 1 0
# 
# $b
# $b[[1]]
# [1] 10 20 30
# $b[[2]]
# [1] 1 2 3
# 
# $c
# $c[[1]]
# [1]  9 12 13
# $c[[2]]
# NULL

我已经调整了Combine/merge lists by elements names 中给出的解决方案,但这似乎不适用于这种数据结构。

这是我尝试过的:

l <- list(l.1, l.2)
keys <- unique(unlist(lapply(l, names)))
do.call(mapply, c(FUN=c, lapply(l, `[`, keys)))

感谢您的帮助。

【问题讨论】:

【参考方案1】:

受 josilber 的回答启发,这里我们不对子列表的长度进行硬编码,而是使用lapply 在结果中创建它们:

keys <- unique(c(names(l.1), names(l.2)))
setNames(lapply(keys, function(key) 
    l1 <- l.1[[key]]
    l2 <- l.2[[key]]
    len <- max(length(l1), length(l2))

    lapply(seq(len), function(i) c(l1[[i]], l2[[i]]))
  ),
  keys)

【讨论】:

感谢您的回答。在此处查看我的后续问题:***.com/questions/23493873/…【参考方案2】:

您可以使用lapply 操作键来执行此合并:

keys <- unique(c(names(l.1), names(l.2)))
setNames(lapply(keys, function(key) list(c(l.1[[key]][[1]], l.2[[key]][[1]]),
                                         c(l.1[[key]][[2]], l.2[[key]][[2]]))),
         keys)
# $a
# $a[[1]]
# [1] 10 20
# 
# $a[[2]]
# [1] 1 0
# 
# $b
# $b[[1]]
# [1] 10 20 30
# 
# $b[[2]]
# [1] 1 2 3
# 
# $c
# $c[[1]]
# [1]  9 12 13
# 
# $c[[2]]
# NULL

【讨论】:

应该是keys &lt;- unique(c(names(l.1), names(l.2)))?即那里不应该有c() 吗?【参考方案3】:

这里是 3 行:

out <- l.1
mnames <- intersect(names(l.1),names(l.2))
out[mnames] <- Map(function(a,b) Map(c,a,b),l.1[mnames],l.2[mnames])

#$a
#$a[[1]]
#[1] 10 20
#$a[[2]]
#[1] 1 0
#
#$b
#$b[[1]]
#[1] 10 20 30
#$b[[2]]
#[1] 1 2 3
#
#$c
#$c[[1]]
#[1]  9 12 13
#$c[[2]]
#NULL

【讨论】:

您能想出一个代码版本,其中 a、b、c 不必硬编码。我想知道您的代码的性能与 matthew-lundberg 的解决方案相比如何。我正在使用以下输入数据来测试性能:library(digest); l.1 &lt;- rep(list(list(c(10,20), NULL),list(c(10,20,30), NULL), list(c(9,12,13), NULL)), 10000); names(l.1) &lt;- sapply(sample(1:30000, 30000, replace=FALSE), digest); l.2 &lt;- rep(list(list(NULL,c(1,0)),list(NULL,c(1,2,3))), 10000); names(l.2) &lt;- names(l.1)[1:20000]【参考方案4】:

这是一种嵌套的合并函数,似乎可以产生您想要的输出。我觉得应该有一种更简单的方法,但我想不出一个。它会优先选择第一个参数的值,但如果有匹配的名称或索引,它将与第二个参数的值合并。

nestedMerge<-function(a,b) 
    if(is.list(a) & is.list(b)) 
        out<-list()
        if(!is.null(names(a))) 
            for(n in names(a)) 
                if(n %in% names(b) && !is.null(b[[n]])) 
                    out<-append(out, list(Recall(a[[n]], b[[n]])))
                 else 
                    out<-append(out, list(a[[n]]))
                
                names(out)[length(out)]<-n
            
         else 
            for(i in seq_along(a))
                if(i <=length(b) && !is.null(b[[i]])) 
                    out<-append(out, Recall(a[[i]], b[[i]]))
                 else 
                    out<-append(out, list(a[[i]]))
                
        
        return(out)
     else 
        return(list(c(a,b)))
    


#and now, use the function
nestedMerge(l.1,l.2)

【讨论】:

是的,这是不必要的复杂,允许多级递归和不同的索引方式。对于这个确切的问题,@thelatemail 的解决方案可能更好、更容易理解。 @rawr 我必须在测试时更改了函数的名称。它应该调用自己。我已经更新了代码。 我就是这么想的。一如既往的好解决方案【参考方案5】:

这是一个额外的解决方案。它使用mapplyc 组合列表:

## get all possible names
l.names <- union(names(l.1), names(l.2)) 
## combine lists
r <- mapply(c, l.1[l.names], l.2[l.names]) 
## get rid of NULL entries
l.3 <- sapply(names(r), 
              function(x) r[[x]][!sapply(r[[x]], is.null)], USE.NAMES=TRUE)

我根据 on this SO question on merging two lists 和 this R help question on how to delete null elements in a list 找到的答案改编了这个答案。

第一行收集两个列表中至少一个中存在的名称(即所有可能的名称)。第二行使用mapplyc 和列表索引以及先前收集的名称来组合列表,尽管存在额外的NULL 条目。第三行删除了这些NULL 条目,同时保留了列表名称。

请注意,此答案确实删除了列表元素 cNULL 条目。

【讨论】:

以上是关于按元素名称组合/合并列表(列表中的列表)的主要内容,如果未能解决你的问题,请参考以下文章

合并 Pandas 列中的列表,其中列名在列表中

5 组合数据类型

将特定值的元素与列表中的相邻元素合并

合并两个列表并在给定列表 2 的情况下输出列表 1 的所有可能组合

试图将 3 个列表中的元素组合(连接)为一个新列表 [重复]

在R中,从列表中的文件夹中读取文件,并按文件名(无文件格式)分配列表元素名称(.fa)