Mapping one list to another

Viewed 112

There are two lists of lists, one contains only values:

lists <- list(list(c(0, 0), c(2, 2, 2), c(3, 4, 4, 5), c(5, 6, 7, 5)), 
    list(c(0, 0), c(1, 1, 2), c(5, 5, 5), c(6, 6, 7, 7)))

> lists

[[1]]
[[1]][[1]]
[1] 0 0

[[1]][[2]]
[1] 2 2 2

[[1]][[3]]
[1] 3 4 4 5

[[1]][[4]]
[1] 5 6 7 5


[[2]]
[[2]][[1]]
[1] 0 0

[[2]][[2]]
[1] 1 1 2

[[2]][[3]]
[1] 5 5 5

[[2]][[4]]
[1] 6 6 7 7

And the other list contains only corresponding names:

names <- list(list(c(1, 2), c(1, 2, 3), c(1, 2, 3, 4), c(1, 2, 3, 4)), 
    list(c(1, 2), c(1, 2, 3), c(1, 2, 3), c(1, 2, 3, 4)))

> names

[[1]]
[[1]][[1]]
[1] 1 2

[[1]][[2]]
[1] 1 2 3

[[1]][[3]]
[1] 1 2 3 4

[[1]][[4]]
[1] 1 2 3 4


[[2]]
[[2]][[1]]
[1] 1 2

[[2]][[2]]
[1] 1 2 3

[[2]][[3]]
[1] 1 2 3

[[2]][[4]]
[1] 1 2 3 4

The two lists of lists have exactly the same structure and number of elements. How can I make each element in the list names to be the name of each corresponding element in the list lists (and add a "t" as prefix), like the following?

[[1]][[1]]
t1 t2
0  0

[[1]][[2]]
t1 t2 t3
2  2  2

[[1]][[3]]
t1 t2 t3 t4
3  4  4  5

[[1]][[4]]
t1 t2 t3 t4
5  6  7  5


[[2]]
[[2]][[1]]
t1 t2
0  0

[[2]][[2]]
t1 t2 t3
1  1  2

[[2]][[3]]
t1 t2 t3
5  5  5

[[2]][[4]]
t1 t2 t3 t4
6  6  7  7
3 Answers

You could write a recursive function:

library(purrr)
fun <- function(x, y){
  modify2(x, y, ~if(is_list(.x)) fun(.x, .y) 
          else set_names(.x, paste0('t', .y)))
}

fun(lists, names)
[[1]]
[[1]][[1]]
t1 t2 
 0  0 

[[1]][[2]]
t1 t2 t3 
 2  2  2 

[[1]][[3]]
t1 t2 t3 t4 
 3  4  4  5 

[[1]][[4]]
t1 t2 t3 t4 
 5  6  7  5 


[[2]]
[[2]][[1]]
t1 t2 
 0  0 

[[2]][[2]]
t1 t2 t3 
 1  1  2 

[[2]][[3]]
t1 t2 t3 
 5  5  5 

[[2]][[4]]
t1 t2 t3 t4 
 6  6  7  7 

Using a double loop is a bit simpler to follow. First create tnames with the same list structure as lists:

tnames <- relist(rapply(names, function(x) paste0("t", x)), names)
for (i in seq(length(lists))) {
    for(j in seq(length(lists[[i]]))) {
        names(lists[[i]][[j]]) <- tnames[[i]][[j]]
    }
}

First a hint: names isn't a good name for an object, since names() is a base R function.

You can transform your list names by multiple uses of lapply

my_names <- lapply(
  names, 
  function(x) lapply(x, function(y) paste0("t", y))
  )

into

[[1]]
[[1]][[1]]
[1] "t1" "t2"

[[1]][[2]]
[1] "t1" "t2" "t3"

[[1]][[3]]
[1] "t1" "t2" "t3" "t4"

[[1]][[4]]
[1] "t1" "t2" "t3" "t4"


[[2]]
[[2]][[1]]
[1] "t1" "t2"

[[2]][[2]]
[1] "t1" "t2" "t3"

[[2]][[3]]
[1] "t1" "t2" "t3"

[[2]][[4]]
[1] "t1" "t2" "t3" "t4"

Next we iterate through your lists assigning the names:

my_lists <- lapply(
  seq_along(lists),
  function(k) lapply(
    seq_along(lists[[k]]), 
    function(n, k) { 
      names(lists[[k]][[n]]) <- my_names[[k]][[n]]
      lists[[k]][[n]] 
      },
    k = k)
  )

my_list
# [[1]]
# [[1]][[1]]
# t1 t2 
# 0  0 
# 
# [[1]][[2]]
# t1 t2 t3 
# 2  2  2 
# 
# [[1]][[3]]
# t1 t2 t3 t4 
# 3  4  4  5 
# 
# [[1]][[4]]
# t1 t2 t3 t4 
# 5  6  7  5 
# 
# 
# [[2]]
# [[2]][[1]]
# t1 t2 
# 0  0 
# 
# [[2]][[2]]
# t1 t2 t3 
# 1  1  2 
# 
# [[2]][[3]]
# t1 t2 t3 
# 5  5  5 
# 
# [[2]][[4]]
# t1 t2 t3 t4 
# 6  6  7  7 

I'm almost sure there are more elegant ways to complete this task, but at least this seems to work.

Related