Home > Enterprise >  How to Effectively Join Two Lists Elementwise by Element Name
How to Effectively Join Two Lists Elementwise by Element Name

Time:12-03

I wonder if there is an effective (without loops) method of joining two lists by names of their elements. I checked here but this did not help me as well as tried to access names from sapply() as on the answer from here.

Say I have the following lists:

mylist1 <- list(region1 = 1:3, region2 = 5:7)
> mylist1
$region1
[1] 1 2 3

$region2
[1] 5 6 7

and

mylist2 <- list(region1 = "#E8C506", region2 = "#F3B508")
$region1
[1] "#E8C506"

$region2
[1] "#F3B508"

How can I get joined list by element names:

mylist3 <- list(region1 = list(1:3, "#E8C506"), region2 = list(5:7, "#F3B508"))
> mylist3
$region1
$region1[[1]]
[1] 1 2 3

$region1[[2]]
[1] "#E8C506"


$region2
$region2[[1]]
[1] 5 6 7

$region2[[2]]
[1] "#F3B508"

CodePudding user response:

Relying heavily on the answers from @Ajar and @Flodel to Combine/merge lists by elements names, this maps into list's instead of a vectors (c) to achieve your end:

Using base:

keys <- unique(c(names(mylist1), names(mylist2)))
setNames(mapply(list, mylist1[keys], mylist2[keys], SIMPLIFY = FALSE), keys)

Using purrr:

library(purrr)

cat_lists <- function(list1, list2) {  

  keys <- unique(c(names(list1), names(list2)))
  map2(list1[keys], list2[keys], list) |>
    set_names(keys)  

}

reduce(list(mylist1, mylist2), cat_lists)

Output:

$region1
$region1[[1]]
[1] 1 2 3

$region1[[2]]
[1] "#E8C506"


$region2
$region2[[1]]
[1] 5 6 7

$region2[[2]]
[1] "#F3B508"

CodePudding user response:

If the elements are identical in both lists you can use purrr::transpose():

library(purrr)

transpose(list(mylist1, mylist2))

$region1
$region1[[1]]
[1] 1 2 3

$region1[[2]]
[1] "#E8C506"


$region2
$region2[[1]]
[1] 5 6 7

$region2[[2]]
[1] "#F3B508"

Note tranpose() uses the first list as a template and matches subsequent list elements by name, so if the elements are different across lists, you need to ensure all names are first present in the first list, e.g.:

mylist3 <- list(region1 = 1:3, region2 = 5:7, region3 = 5:7)
mylist4 <- list(region1 = "#E8C506", region2 = "#F3B508", region4 = "#F00008")

l <- list(mylist3, mylist4)
l_names <- unique(unlist(lapply(l, names)))
mylist3[l_names] <- mylist3[l_names]

transpose(list(mylist3, mylist4))

$region1
$region1[[1]]
[1] 1 2 3

$region1[[2]]
[1] "#E8C506"


$region2
$region2[[1]]
[1] 5 6 7

$region2[[2]]
[1] "#F3B508"


$region3
$region3[[1]]
[1] 5 6 7

$region3[[2]]
NULL


$region4
$region4[[1]]
NULL

$region4[[2]]
[1] "#F00008"

CodePudding user response:

I hope this works.

list12 <- mapply(list, mylist1 , mylist2 , SIMPLIFY=FALSE)
  • Related