15

I have a list of lists that have names.

I want to add them all together into a dataframe but keep all the columns

past_earnings_lists[1]

successfully returns one list from the list of lists

names(past_earnings_lists)[1]

successfully returns the name of the list

past_earnings <- melt(past_earnings_lists)

puts all the data in one data frame but doesn't keep structure

past_earnings <- as.data.frame.matrix(past_earnings_lists$ADBE)

Successfully takes one list and keeps the structure but doesn't add the name of the list to the dataframe.

For example, adbe has 7 columns and 30 rows; I want it to add an 8th column with the name, adbe, and append it to a dataframe with all the other lists doing the same.

structure

I want a dataframe with the results being:
  sym  v1 v2 v3 v4 v5 v6 v7
1 adbe  1  2  3  4  5  6  7
2 adbe  1  2  3  4  5  6  7
3 air   1  2  3  4  5  6  7
4 air   1  2  3  4  5  6  7
5 alog  1  2  3  4  5  6  7
and so on
AndrewGB
  • 16,126
  • 5
  • 18
  • 49
Bryanzpope
  • 957
  • 1
  • 9
  • 20
  • 7
    this isn't going to fly without a reproducible example – B Williams Sep 19 '17 at 21:55
  • 1
    Agreed that its unlikely you will find help without providing data structure to make it a reproducible example, but you may find the `bind_rows` function from `dplyr` helpful using the `.id` parameter to concatenate your lists while generating a new variable identifying the name of the list. http://dplyr.tidyverse.org/reference/bind.html – dshkol Sep 19 '17 at 22:38
  • there, i've added a screenshot – Bryanzpope Sep 19 '17 at 22:49
  • It's still not clear. Do you have a list, or a list of lists? Can you include the output of `str` or `dput` of `past_earnings_list`? – mikeck Sep 20 '17 at 05:38
  • Also note that doing `mylist[1]` returns a *sublist*, whereas `mylist[[1]]` returns the element itself (see the double brackets). – mikeck Sep 20 '17 at 05:40

3 Answers3

38

This might work

library(purrr)
ans <- map_df(past_earnings_lists, ~as.data.frame(.x), .id="id")

It uses map_df, which will map over lists and convert the result to data frames (if possible). Use the .id argument to add names to each data frame as a column.

CPak
  • 13,260
  • 3
  • 30
  • 48
3

as @dshkol commented, the easiest is to use dplyr::bind_rows:

d = data.frame(letter = LETTERS, number = 1:26)
d.list = list(d1 = d, d2 = d)
d.all = dplyr::bind_rows(d.list, .id = "variable")

You can also do this in base R with rbind and do.call:

d.all = do.call(rbind, d.list)

However, this will not give you a column containing the list names. You could parse it from the row.names though:

d.all["variable"] = unlist(lapply(
  strsplit(row.names(d.all), ".", fixed = TRUE), function(x) x[[1]])
)

Alternatively, loop through your data frames frames and add the label manually prior to binding:

for (n in names(d.list))
  d.list[[n]]['name'] = n
d.all = do.call(rbind, d.list)

However, it looks like your data frames don't have column names. I think you'll need to fix that for either solution to work.

mikeck
  • 3,534
  • 1
  • 26
  • 39
2

@mikeck was in right track. Splitting string using . is tricky as . regex matches any character. So we need escape character \ before the .. For anyone who wants to accomplish this with base R, you may try this:

df <- do.call(rbind, list)
df$listname <- lapply(strsplit(row.names(df), "\\."), '[[', 1)