Reputation: 436
I have a nested list of lists:
data = list(a = list(1, 2, 3), b = list("foo"), c = list("toast", "onions"))
How can I convert this into a single row of a data.frame or tibble? I would like the lists with more than one element (a
and c
here) to be kept as lists, and the single-element (b
) to be a regular value.
Expected output is:
# A tibble: 1 x 3
a b c
<list> <chr> <list>
1 <list [3]> foo <list [2]>
Upvotes: 5
Views: 792
Reputation: 887138
An option is to create a two column dataset with aggregate
from base R
aggregate(values ~ ind, stack(data), list)
Upvotes: 0
Reputation: 388982
You can use enframe
+ pivot_wider
tibble::enframe(data) %>% tidyr::pivot_wider()
# a b c
# <list> <list> <list>
#1 <list [3]> <list [1]> <list [2]>
To get length one column as vector we can add :
library(dplyr)
tibble::enframe(data) %>%
tidyr::pivot_wider() %>%
summarise(across(.fns = ~if(length(unlist(.)) == 1) unlist(.) else .))
# a b c
# <list> <chr> <list>
#1 <list [3]> foo <list [2]>
Upvotes: 1
Reputation: 33488
data[] <- lapply(data, function(x) if (length(x) == 1) x[[1]] else list(x))
data.table::setDF(data)
# > str(data)
# 'data.frame': 1 obs. of 3 variables:
# $ a:List of 1
# ..$ :List of 3
# .. ..$ : num 1
# .. ..$ : num 2
# .. ..$ : num 3
# $ b: chr "foo"
# $ c:List of 1
# ..$ :List of 2
# .. ..$ : chr "toast"
# .. ..$ : chr "onions"
Upvotes: 1
Reputation: 101403
What about this?
> as_tibble_row(Map(function(x) ifelse(length(x)==1,unlist(x),list(x)),data))
# A tibble: 1 x 3
a b c
<list> <chr> <list>
1 <list [3]> foo <list [2]>
Upvotes: 2