简体   繁体   中英

How to bind rows of dataframes in separate elements within a list of lists

Let's suppose I have a list of lists as follows:

set.seed(111)
lst_1 = rep(list(list()), 3) 

lst_1[[1]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[2]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[3]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))

where each list element (1, 2 and 3) is a list which contains two data.frames.

How can I sequentially bind the rows of the first data.frame within each (sub)list? ie lst_1[[1]][[1]] + lst_1[[2]][[1]] + lst_1[[3]][[1]] , and eventually do the same for the second data.frame ?

Here is my desired output, which is achieved manually with a for loop, however my real list of lists is much larger:

lst_out = rep(list(list()), 2) 

for (i in 1:2) {
lst_out[[i]] = rbind(lst_1[[1]][[i]], lst_1[[2]][[i]], lst_1[[3]][[i]])
}

If I'm interpreting correctly, the base R solution should be pretty straight forward. Map the rbind function over each part of the 3 inputs in lst_1 :

do.call(Map, c(rbind, lst_1))

This is a slightly obscured way of calling the expanded Map line of:

Map(rbind, lst_1[[1]], lst_1[[2]], lst_1[[3]])

Which starts to look a lot like your original for loop, and gives the same result as doing it via do.call :

identical(
  do.call(Map, c(rbind, lst_1)),
  Map(rbind, lst_1[[1]], lst_1[[2]], lst_1[[3]])
)
#[1] TRUE

Checks out with the intended result too:

identical(lst_out, do.call(Map, c(rbind, lst_1)))
#[1] TRUE

I think the simplest way is to simply purrr::transpose the list, so that instead of three sublists with two dataframe elements, you have two sublists with three dataframe elements. This means that the dataframes to bind are all in the same sublist, so iteration is much simpler and we can map over the main list. See below, noting that you can just load purrr as dplyr::bind_rows is just a bit faster and tibble::glimpse is for printing only.

library(tidyverse)
set.seed(111)
lst_1 = rep(list(list()), 3) 

lst_1[[1]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[2]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[3]] = list(data.frame(rnorm(5)), data.frame(rnorm(5)))

lst_1 %>%
  transpose %>%
  map(bind_rows) %>%
  glimpse
#> List of 2
#>  $ :'data.frame':    15 obs. of  1 variable:
#>   ..$ rnorm.5.: num [1:15] 0.235 -0.331 -0.312 -2.302 -0.171 ...
#>  $ :'data.frame':    15 obs. of  1 variable:
#>   ..$ rnorm.5.: num [1:15] 0.14 -1.497 -1.01 -0.948 -0.494 ...

Created on 2019-04-20 by the reprex package (v0.2.1)

Base R solution

set.seed(111)
lst_1 <- rep(list(list()), 3) 

lst_1[[1]] <- list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[2]] <- list(data.frame(rnorm(5)), data.frame(rnorm(5)))
lst_1[[3]] <- list(data.frame(rnorm(5)), data.frame(rnorm(5)))

lst_out_2 <- list()

for (i in 1:2) { 
  lst_out_2[[i]] <- do.call('rbind', sapply(lst_1, `[`, i))
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM