Search code examples
rdataframenested-lists

Combining lists of lists of dataframes


I have a list of lists of dataframes, where each dataframe has a name according to its position in its list. I want to rbind my dataframes together according to their name.

A1 <- data.frame(cars*rnorm(50,2))
B1 <- data.frame(cars*rnorm(60,2))
C1 <- data.frame(cars*rnorm(70,2))

A2 <- data.frame(cars*rnorm(50,2))
B2 <- data.frame(cars*rnorm(60,2))
C2 <- data.frame(cars*rnorm(70,2))

A3 <- data.frame(cars*rnorm(50,2))
B3 <- data.frame(cars*rnorm(60,2))
C3 <- data.frame(cars*rnorm(70,2))

Gen1 <- list(A1,B1,C1) ; names(Gen1) <- c('A','B','C')
Gen2 <- list(A2,B2,C2) ; names(Gen2) <- c('A','B','C')
Gen3 <- list(A3,B3,C3) ; names(Gen3) <- c('A','B','C')

Data1 <- list(Gen1, Gen2, Gen3) ; names(Data1) <- c('Gen1', 'Gen2', 'Gen3')

# Example of desired output
A_values <- rbind(Gen1$A, Gen2$A, Gen3$A)
B_values <- rbind(Gen1$B, Gen2$B, Gen3$B)
C_values <- rbind(Gen1$C, Gen2$C, Gen3$C)
output <- list(A_values, B_values, C_values)

output illustrates what I'm trying to get, but I want to use an apply family function on Data1 where I don't have to specify each item in each list by name.

This post covers a similar issue issue, but the solution using lapply leads to a list grouped by the the "upper" list level (Gen) rather than the "lower" list level (A, B, or C).

TEST <- lapply(split(Data1, names(Data1)), function(i){
    xsub <- do.call(c, unname(i))
    lapply(split(xsub, names(xsub)), function(j) do.call(rbind, unname(j)))
})
str(TEST)
List of 3
 $ Gen1:List of 3
  ..$ A:'data.frame':   50 obs. of  2 variables:
  .. ..$ A.speed: num [1:50] 10.54 8.98 6.12 16.78 7.25 ...
  .. ..$ A.dist : num [1:50] 5.27 22.44 3.5 52.74 14.5 ...
  ..$ B:'data.frame':   50 obs. of  2 variables:
  .. ..$ B.speed: num [1:50] 3.699 3.199 13.915 -0.945 9.957 ...
  .. ..$ B.dist : num [1:50] 5.54 36.25 17.13 -5.3 37.93 ...
  ..$ C:'data.frame':   50 obs. of  2 variables:
  .. ..$ C.speed: num [1:50] 14.72 12.95 8.58 16.55 13.02 ...
  .. ..$ C.dist : num [1:50] 2.11 11.98 3.82 32.4 8.97 ...
 $ Gen2:List of 3
 $ Gen3:List of 3

I've also tried tapply with no success. Any help is much appreciated. Thanks!


Solution

  • I ultimately achieved this using the base R approach: do.call(Map, c(rbind, Data1))

    The tidyverse approach using list_transpose also works.