Merge Two Lists in R

后端 未结 6 1007
南旧
南旧 2020-11-28 22:52

I have two lists

first = list(a = 1, b = 2, c = 3)
second = list(a = 2, b = 3, c = 4)

I want to merge these two lists so the final product

相关标签:
6条回答
  • 2020-11-28 23:30

    Here are two options, the first:

    both <- list(first, second)
    n <- unique(unlist(lapply(both, names)))
    names(n) <- n
    lapply(n, function(ni) unlist(lapply(both, `[[`, ni)))
    

    and the second, which works only if they have the same structure:

    apply(cbind(first, second),1,function(x) unname(unlist(x)))
    

    Both give the desired result.

    0 讨论(0)
  • 2020-11-28 23:31

    This is a very simple adaptation of the modifyList function by Sarkar. Because it is recursive, it will handle more complex situations than mapply would, and it will handle mismatched name situations by ignoring the items in 'second' that are not in 'first'.

    appendList <- function (x, val) 
    {
        stopifnot(is.list(x), is.list(val))
        xnames <- names(x)
        for (v in names(val)) {
            x[[v]] <- if (v %in% xnames && is.list(x[[v]]) && is.list(val[[v]])) 
                appendList(x[[v]], val[[v]])
            else c(x[[v]], val[[v]])
        }
        x
    }
    
    > appendList(first,second)
    $a
    [1] 1 2
    
    $b
    [1] 2 3
    
    $c
    [1] 3 4
    
    0 讨论(0)
  • 2020-11-28 23:39
    merged = map(names(first), ~c(first[[.x]], second[[.x]])
    merged = set_names(merged, names(first))
    

    Using purrr. Also solves the problem of your lists not being in order.

    0 讨论(0)
  • 2020-11-28 23:48

    If lists always have the same structure, as in the example, then a simpler solution is

    mapply(c, first, second, SIMPLIFY=FALSE)
    
    0 讨论(0)
  • 2020-11-28 23:48

    In general one could,

    merge_list <- function(...) by(v<-unlist(c(...)),names(v),base::c)
    

    Note that the by() solution returns an attributed list, so it will print differently, but will still be a list. But you can get rid of the attributes with attr(x,"_attribute.name_")<-NULL. You can probably also use aggregate().

    0 讨论(0)
  • 2020-11-28 23:52

    Here's some code that I ended up writing, based upon @Andrei's answer but without the elegancy/simplicity. The advantage is that it allows a more complex recursive merge and also differs between elements that should be connected with rbind and those that are just connected with c:

    # Decided to move this outside the mapply, not sure this is 
    # that important for speed but I imagine redefining the function
    # might be somewhat time-consuming
    mergeLists_internal <- function(o_element, n_element){
      if (is.list(n_element)){
        # Fill in non-existant element with NA elements
        if (length(n_element) != length(o_element)){
          n_unique <- names(n_element)[! names(n_element) %in% names(o_element)]
          if (length(n_unique) > 0){
            for (n in n_unique){
              if (is.matrix(n_element[[n]])){
                o_element[[n]] <- matrix(NA, 
                                         nrow=nrow(n_element[[n]]), 
                                         ncol=ncol(n_element[[n]]))
              }else{
                o_element[[n]] <- rep(NA, 
                                      times=length(n_element[[n]]))
              }
            }
          }
    
          o_unique <- names(o_element)[! names(o_element) %in% names(n_element)]
          if (length(o_unique) > 0){
            for (n in o_unique){
              if (is.matrix(n_element[[n]])){
                n_element[[n]] <- matrix(NA, 
                                         nrow=nrow(o_element[[n]]), 
                                         ncol=ncol(o_element[[n]]))
              }else{
                n_element[[n]] <- rep(NA, 
                                      times=length(o_element[[n]]))
              }
            }
          }
        }  
    
        # Now merge the two lists
        return(mergeLists(o_element, 
                          n_element))
    
      }
      if(length(n_element)>1){
        new_cols <- ifelse(is.matrix(n_element), ncol(n_element), length(n_element))
        old_cols <- ifelse(is.matrix(o_element), ncol(o_element), length(o_element))
        if (new_cols != old_cols)
          stop("Your length doesn't match on the elements,",
               " new element (", new_cols , ") !=",
               " old element (", old_cols , ")")
      }
    
      return(rbind(o_element, 
                   n_element, 
                   deparse.level=0))
      return(c(o_element, 
               n_element))
    }
    mergeLists <- function(old, new){
      if (is.null(old))
        return (new)
    
      m <- mapply(mergeLists_internal, old, new, SIMPLIFY=FALSE)
      return(m)
    }
    

    Here's my example:

    v1 <- list("a"=c(1,2), b="test 1", sublist=list(one=20:21, two=21:22))
    v2 <- list("a"=c(3,4), b="test 2", sublist=list(one=10:11, two=11:12, three=1:2))
    mergeLists(v1, v2)
    

    This results in:

    $a
         [,1] [,2]
    [1,]    1    2
    [2,]    3    4
    
    $b
    [1] "test 1" "test 2"
    
    $sublist
    $sublist$one
         [,1] [,2]
    [1,]   20   21
    [2,]   10   11
    
    $sublist$two
         [,1] [,2]
    [1,]   21   22
    [2,]   11   12
    
    $sublist$three
         [,1] [,2]
    [1,]   NA   NA
    [2,]    1    2
    

    Yeah, I know - perhaps not the most logical merge but I have a complex parallel loop that I had to generate a more customized .combine function for, and therefore I wrote this monster :-)

    0 讨论(0)
提交回复
热议问题