Home > OS >  How to unlist a list and keep the names of the top level as a new variable in R
How to unlist a list and keep the names of the top level as a new variable in R

Time:04-14

is there a simple way to unlist a list and keep the names of one level as a new variable?

Working example:

# Input list
my_list <- list(Ticker1 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 1:10),
                Ticker2 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 11:20),
                Ticker3 = list(date = seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), Value = 21:30))

# Desired data frame
my_df_goal <- as.data.frame(list(Ticker = c(rep("Ticker1", 10), rep("Ticker2", 10), rep("Ticker3", 10)),
                                 date = rep(seq.Date(as.Date('2021-01-01'), as.Date('2021-01-10'), by = 'day'), 3),
                                 Value = 1:30))

There are similar questions regarding unlisting on stackoverflow, but I wasn't able to solve my problem.

One way would probably be

my_df <- as.data.frame(rlist::list.flatten(my_list))

# Same result:
my_df2 <- as.data.frame(unlist(my_list,recursive = F))

#Edit: just noticed that you do not need to unlist first to get the same result:
my_df3 <- as.data.frame(my_list)

and then try to extract the Ticker from the new variable name. But I hope there is an easier solution.

I also tried my_df4 <- reshape2::melt(my_list), but this is not helpful. I have a feeling that the purrr package may have this functionality, but I am not familiar with the package.

I am happy about any help!

Thanks a lot

CodePudding user response:

One way:

library(tidyverse)

my_list %>% 
  enframe() %>% 
  unnest_wider(value) %>% 
  unnest(cols = c(date, Value))

#  A tibble: 30 x 3
   name    date       Value
   <chr>   <date>     <int>
 1 Ticker1 2021-01-01     1
 2 Ticker1 2021-01-02     2
 3 Ticker1 2021-01-03     3
 4 Ticker1 2021-01-04     4
 5 Ticker1 2021-01-05     5
 6 Ticker1 2021-01-06     6
 7 Ticker1 2021-01-07     7
 8 Ticker1 2021-01-08     8
 9 Ticker1 2021-01-09     9
10 Ticker1 2021-01-10    10
# ... with 20 more rows

CodePudding user response:

dplyrs bind_rows should do the trick:

library(dplyr)

bind_rows(my_list, .id = "Ticker")

This returns

# A tibble: 30 x 3
   Ticker  date       Value
   <chr>   <date>     <int>
 1 Ticker1 2021-01-01     1
 2 Ticker1 2021-01-02     2
 3 Ticker1 2021-01-03     3
 4 Ticker1 2021-01-04     4
 5 Ticker1 2021-01-05     5
 6 Ticker1 2021-01-06     6
 7 Ticker1 2021-01-07     7
 8 Ticker1 2021-01-08     8
 9 Ticker1 2021-01-09     9
10 Ticker1 2021-01-10    10
# ... with 20 more rows

CodePudding user response:

Here's a way using lapply combined with some dplyr operations.

library(tidyverse)

do.call(rbind, lapply(my_list, data.frame)) %>% 
  rownames_to_column("Ticker") %>% 
  mutate(Ticker = gsub("\\..*$", "", Ticker))

    Ticker       date Value
1  Ticker1 2021-01-01     1
2  Ticker1 2021-01-02     2
3  Ticker1 2021-01-03     3
4  Ticker1 2021-01-04     4
5  Ticker1 2021-01-05     5
6  Ticker1 2021-01-06     6
...
  • Related