我有两个列表,其元素名称部分重叠,我需要逐个元素地合并/组合成一个列表:
我的问题与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")
因此,数据的类型为“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
合并两个列表的结果应如下所示:
# $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)))
我感谢任何帮助。
答案 0 :(得分:6)
您可以使用密钥操作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
答案 1 :(得分:6)
受到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)
答案 2 :(得分:4)
这里有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
答案 3 :(得分:1)
这是一种嵌套合并函数,它似乎可以产生您想要的输出。我觉得应该有一个更简单的方法,但我不能想到一个。它将优先使用第一个参数中的值,但如果存在匹配的名称或索引,它将与第二个参数中的值合并。
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)
答案 4 :(得分:0)
这是一个额外的解决方案。它使用mapply
和c
来组合列表:
## 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找到的答案调整了这个答案。
第一行收集两个列表中至少一个列表中存在的名称(即所有可能的名称)。第二行使用mapply
,c
,并使用先前收集的名称列出索引以组合列表,尽管存在额外的NULL
个条目。第三行删除了这些NULL
条目,同时保留了列表名称。
请注意,此答案确实消除了列表元素NULL
的{{1}}条目。