简体   繁体   English

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

[英]Combine/merge lists by elements names (list in list)

I have two lists, whose elements have partially overlapping names, which I need to merge/combine together into a single list, element by element: 我有两个列表,其元素具有部分重叠的名称,我需要逐个元素地合并/组合成一个列表:

My question is related to Combine/merge lists by elements names , but the data structure in my example is more complicated and thus, the solution provided under the above mentioned link does not work in this case. 我的问题与元素名称的组合/合并列表有关,但我的例子中的数据结构更复杂,因此,在这种情况下,上述链接提供的解决方案不起作用。

Here is a simplified toy example: 这是一个简化的玩具示例:

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

Thus, the data is of type "list in list" and looks like this: 因此,数据的类型为“list in list”,如下所示:

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

The result of merging both lists should look like this: 合并两个列表的结果应如下所示:

# $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

I already adapted the solution given in Combine/merge lists by elements names , but this seems not to work for this data structure. 我已经按照元素名称调整了Combine / merge列表中给出的解决方案,但这似乎不适用于此数据结构。

Here is what I tried: 这是我尝试过的:

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

I appreciate any help. 我感谢任何帮助。

You can use lapply operating on the keys to do this merge: 您可以使用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

Inspired by josilber's answer, here we do not hard-code the length of the sublists and use lapply to create them in the result: 受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)

Here you go in 3 lines: 这里有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

This is a kind of a nested merge function which seems to produce the output you desire. 这是一种嵌套合并函数,它似乎可以产生您想要的输出。 I feel like there should be a more simple way but I can't think of one. 我觉得应该有一个更简单的方法,但我想不出一个。 It will prefer values from the first parameter, but will merge with values from the second parameter if there is a matching name or index. 它将优先使用第一个参数中的值,但如果存在匹配的名称或索引,它将与第二个参数中的值合并。

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)

Here is an additional solution. 这是一个额外的解决方案。 It uses mapply with c to combine the lists: 它使用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)

I adapted this answer from answers found on this SO question on merging two lists and this R help question on how to delete null elements in a list . 根据这个SO问题找到了关于合并两个列表的答案以及如何删除列表中的空元素的R帮助问题

The first line gathers the names present in at least one of the two lists (ie all possible names). 第一行收集两个列表中至少一个列表中存在的名称(即所有可能的名称)。 The second line uses mapply , c , and list indexing with the previously gathered names to combine the lists, albeit with extra NULL entries present. 第二行使用mapplyc和list索引与先前收集的名称组合列表,尽管存在额外的NULL条目。 The third line gets rid of these NULL entries while preserving list names. 第三行删除这些NULL条目,同时保留列表名称。

Note this answer does get rid of the NULL entry for list element c . 注意这个答案确实摆脱了列表元素cNULL条目。

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

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