I've got a list with a uniform structure: each item is itself a list of commonly named data.frames. I want to find all the items with the same name in the 2nd level and make them a single data.frame. Here's an example list like this:
MyList <- list("A" = list("apples" = data.frame(X = 1:5,
Source = "A"),
"mangoes" = data.frame(X = 1:5,
Source = "A")),
"B" = list("apples" = data.frame(X = 1:5,
Source = "B"),
"mangoes" = data.frame(X = 1:5,
Source = "B")),
"C" = list("apples" = data.frame(X = 1:5,
Source = "C"),
"mangoes" = data.frame(X = 1:5,
Source = "C")))
I'd like to create a new list with a single level instead of two levels, and I need all the "apples" to be a single data.frame and all the "mangoes" to be a single data.frame. It would look like this:
MyNewList <- list("apples" = bind_rows(data.frame(X = 1:5,
Source = "A"),
data.frame(X = 1:5,
Source = "B"),
data.frame(X = 1:5,
Source = "C")),
"mangoes" = bind_rows(data.frame(X = 1:5,
Source = "A"),
data.frame(X = 1:5,
Source = "B"),
data.frame(X = 1:5,
Source = "C")))
This seems like a job for map or pluck from purrr, but I've always found the syntax for those to be confusing. Here's what I've tried:
Trying to get all the "apples" as a place to start:
pluck(MyList, 1:3, "apples") # nope; index can't have length > 1
Maybe I can lapply over the names of the items?
lapply(c("apples", "mangoes"),
FUN = function(x) pluck(MyList, x)) # all items are NULL
Maybe map_depth does this?
map_depth(.x = MyList,
.depth = 2,
.f = bind_rows) # not at all what I want
You can iterate over each fruit to bind it into a data frame:
fruits <- c("apples", "mangoes")
out <- lapply(fruits, \(fruit)
dplyr::bind_rows(lapply(MyList, \(x) x[[fruit]]))
) |> setNames(fruits)
identical(out, desired)
# [1] TRUE