FilipW
FilipW

Reputation: 1525

Unlist column in data frame with listed

I have a list with multiple levels that I would like to the data level into a data frame, where the variable chr is collapsed into single strings.

 myList <- list(total_reach = list(4),
                   data = list(list(reach = 2,
                              chr = list("A", "B", "C"),
                              nr = 3,
                              company = "Company A"),
                   list(reach = 2,
                        chr = list("A", "B", "C"),
                        nr = 3,
                        company = "Company B")))

I would like to transform this into a data frame that looks like this:

  reach     chr nr   company
1     2 A, B, C  3 Company A
2     2 A, B, C  3 Company B

Using dplyr and data.table I've come this far.

library(data.table)
library(dplyr)
df <- data.frame(rbindlist(myList[2])) %>% t() %>% as.data.frame()

colnames(df) <- names(myList$data[[1]])
rownames(df) <- c(1:nrow(df))

df$chr <- as.character(df$chr)

df <- df %>%
  mutate_all(funs(unlist(.recursive = F, use.names = F)))

However, chr column contains strings with "list()" wrapped around it.

  reach                 chr nr   company
1     2 list("A", "B", "C")  3 Company A
2     2 list("A", "B", "C")  3 Company B

A) Is there a better way to unlist this kind of list and turn it into a data frame?
B) How do I collapse the lists in chr to strings or factors?

Upvotes: 2

Views: 4025

Answers (3)

moodymudskipper
moodymudskipper

Reputation: 47310

I'm using rbind to put everything together, then I reformat the chr column with sapply

library(magrittr)
myList$data %>%
  do.call(rbind,.) %>%
  transform(chr %<>% sapply(paste,collapse=","))
#   reach   chr nr   company
# 1     2 A,B,C  3 Company A
# 2     2 A,B,C  3 Company B

EDIT a few months later:

One line longer but a more idiomatic tidyverse variation:

library(tidyverse)
myList$data %>%
  map_df(as_tibble)    %>%
  group_by(reach,nr,company) %>%
  summarize_at("chr",paste,collapse=",")

Upvotes: 1

Uwe
Uwe

Reputation: 42544

With data.table you can try

library(data.table)
rbindlist(lapply(myList$data, as.data.table))[, .(chr = toString(chr)), 
                                              by = .(reach, nr, company)]
   reach nr   company     chr
1:     2  3 Company A A, B, C
2:     2  3 Company B A, B, C

Note that there is a difference in using as.data.table or as.data.frame:

rbindlist(lapply(myList$data, as.data.table))
   reach chr nr   company
1:     2   A  3 Company A
2:     2   B  3 Company A
3:     2   C  3 Company A
4:     2   A  3 Company B
5:     2   B  3 Company B
6:     2   C  3 Company B
rbindlist(lapply(myList$data, as.data.frame))
   reach chr..A. chr..B. chr..C. nr   company
1:     2       A       B       C  3 Company A
2:     2       A       B       C  3 Company B

Alternatively, chr can be manipulated before converting the list into a data.table:

rbindlist(lapply(myList$data, function(x) {
    x$chr = toString(x$chr)
    return(as.data.table(x))
}))
   reach     chr nr   company
1:     2 A, B, C  3 Company A
2:     2 A, B, C  3 Company B

Upvotes: 4

akrun
akrun

Reputation: 887098

Here is an option using tidyverse

library(tidyverse)
myList[-1] %>% 
     map_df(transpose)  %>% 
     mutate_at(vars(c('reach', 'nr', 'company')), funs(unlist))

Upvotes: 5

Related Questions