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

时间:2021-07-06 20:24:28

I have two lists, whose elements have partially overlapping names, which I need to merge/combine together into a single list, element by element:

我有两个列表,它们的元素有部分重叠的名称,我需要将它们合并到一个列表中,元素by元素:

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.

我已经根据元素名称对组合/合并列表中给出的解决方案进行了修改,但这似乎并不适用于这个数据结构。

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.

我很感谢任何帮助。

5 个解决方案

#1


6  

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)

#2


6  

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

#3


4  

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

#4


1  

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)

#5


0  

Here is an additional solution. It uses mapply with c to combine the lists:

这里有一个附加的解决方案。它使用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)

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.

我根据在这个问题上找到的答案来回答这个问题,这个问题是关于合并两个列表的问题,这个R帮助问题关于如何删除列表中的空元素。

The first line gathers the names present in at least one of the two lists (i.e. 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. The third line gets rid of these NULL entries while preserving list names.

第一行在两个列表中(即所有可能的名称)中收集至少一个名称。第二行使用mapply、c和列表索引与前面收集的名称组合,以组合列表,尽管有额外的空条目。第三行删除这些空项,同时保留列表名称。

Note this answer does get rid of the NULL entry for list element c.

注意,这个答案确实去掉了list元素c的空项。

#1


6  

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)

#2


6  

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

#3


4  

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

#4


1  

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)

#5


0  

Here is an additional solution. It uses mapply with c to combine the lists:

这里有一个附加的解决方案。它使用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)

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.

我根据在这个问题上找到的答案来回答这个问题,这个问题是关于合并两个列表的问题,这个R帮助问题关于如何删除列表中的空元素。

The first line gathers the names present in at least one of the two lists (i.e. 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. The third line gets rid of these NULL entries while preserving list names.

第一行在两个列表中(即所有可能的名称)中收集至少一个名称。第二行使用mapply、c和列表索引与前面收集的名称组合,以组合列表,尽管有额外的空条目。第三行删除这些空项,同时保留列表名称。

Note this answer does get rid of the NULL entry for list element c.

注意,这个答案确实去掉了list元素c的空项。