Combine/merge lists by elements names (list in list)

a 夏天 提交于 2019-12-19 05:45:23

问题


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:

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


回答1:


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:

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:


You can use lapply operating on the keys to do this merge:

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:


Here you go in 3 lines:

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:


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:


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

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

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.

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



来源:https://stackoverflow.com/questions/23483421/combine-merge-lists-by-elements-names-list-in-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!