Hassan Saif
Hassan Saif

Reputation: 1062

R: Sum together items in multiple lists of different length?

I have the following lists:

l1 <- list(a = 3, b = 4, c = 8, d = 1)

l2 <- list(a = 3, b = 2, c = 5, d = 1, f = 4, g = 13)

How can merge both lists by summing the items in both lists based on their names, as:

l1 + l2 = list(a=6, b=6, c=13, d=2, f=4, g=13)

Upvotes: 4

Views: 654

Answers (3)

Ronak Shah
Ronak Shah

Reputation: 388817

A slightly different approach,

l1 <- list(a = 3, b = 4, c = 8, d = 1)
l2 <- list(a = 3, b = 2, c = 5, d = 1, f = 4, g = 13)
a <- l1[intersect(names(l1), names(l2))] 
b <- l2[intersect(names(l1), names(l2))]
ab <- as.numeric(a) + as.numeric(b)

c <- as.numeric(l1[!(l1 %in% a)])
d <- as.numeric(l2[!(l2 %in% b)])

c(ab, c, d)
# [1]  6  6 13  2  4 13

Upvotes: 0

akrun
akrun

Reputation: 886948

One option would be to melt both the lists to data.frame, merge them, do the rowSums on the numeric columns and convert back to list.

library(reshape2)
d1 <- merge(melt(l1), melt(l2), by='L1', all=TRUE)
setNames(as.list(rowSums(d1[-1], na.rm=TRUE)), d1$L1)
#$a
#[1] 6

#$b
#[1] 6

#$c
#[1] 13

#$d
#[1] 2

#$f
#[1] 4

#$g
#[1] 13

Or we create the unique names of both 'l1' and 'l2' ('nm1'). Loop over 'nm1', replace the NULL elements with 0 and do the +.

 nm1 <- union(names(l1), names(l2))
 lapply(nm1, function(x) {v1 <- l1[[x]]
                          v2 <- l2[[x]]
                         replace(v1, is.null(v1), 0) +
                         replace(v2, is.null(v2), 0)    

     })

Upvotes: 3

Benjamin
Benjamin

Reputation: 17359

You could approach it with dplyr as follows:

l1 <- list(a = 3, b = 4, c = 8, d = 1)
l2 <- list(a = 3, b = 2, c = 5, d = 1, f = 4, g = 13)

library(dplyr)

bind_rows(lapply(list(l1, l2), as.data.frame)) %>%
colSums(na.rm=TRUE) %>%
as.list()

Upvotes: 4

Related Questions