Merge Two Lists in R

RListDataframe

R Problem Overview


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 is

$a
[1] 1 2

$b
[1] 2 3

$c
[1] 3 4

Is there a simple function to do this?

R Solutions


Solution 1 - R

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

mapply(c, first, second, SIMPLIFY=FALSE)

Solution 2 - R

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

Solution 3 - R

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.

Solution 4 - R

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

Solution 5 - R

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.

Solution 6 - R

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().

Solution 7 - R

Following @Aaron left Stack Overflow and @Theo answer, the merged list's elements are in form of vector c. But if you want to bind rows and columns use rbind and cbind.

merged = map(names(first), ~rbind(first[[.x]], second[[.x]])
merged = set_names(merged, names(first))

Solution 8 - R

Using dplyr, I found that this line works for named lists using the same names:

as.list(bind_rows(first, second))

Solution 9 - R

We can do a lapply with c(), and use setNames to assign the original name to the output.

setNames(lapply(1:length(first), function(x) c(first[[x]], second[[x]])), names(first))

$a
[1] 1 2

$b
[1] 2 3

$c
[1] 3 4

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichaelView Question on Stackoverflow
Solution 1 - RAndreiView Answer on Stackoverflow
Solution 2 - RIRTFMView Answer on Stackoverflow
Solution 3 - RAaron left Stack OverflowView Answer on Stackoverflow
Solution 4 - RMax GordonView Answer on Stackoverflow
Solution 5 - RTheoView Answer on Stackoverflow
Solution 6 - RcstaView Answer on Stackoverflow
Solution 7 - RNad PatView Answer on Stackoverflow
Solution 8 - Ruser17980667View Answer on Stackoverflow
Solution 9 - Rbenson23View Answer on Stackoverflow