Is there a pivot_longer equivalent for named lists?

Hi all,

I am manipulating named lists with depth 1 and with elements being vectors of variable lengths.
e.g.

d <- list(a = 1:2, b = 3:7)
d
#> $a
#> [1] 1 2
#> 
#> $b
#> [1] 3 4 5 6 7

I would like to turn these list into data frames for simplicity, such as:

#>   name value
#> 1    a     1
#> 2    a     2
#> 3    b     3
#> 4    b     4
#> 5    b     5
#> 6    b     6
#> 7    b     7

I managed using base-r Map():

do.call("rbind", args = c(Map(\(x, y) data.frame(name = x, value = y), names(d), d), make.row.names = FALSE))

... but I am looking for a more elegant approach (tidy or not) that would be human readable and yet compact.

Any idea very welcome!

PS: I was hoping to discover some nice function hidden within {purrr}, but I probably missed it.

It is somewhat more concise but also ugly in a sense, but here is my attempt (using a function from purrr):

purrr::list_rbind(lapply(d, as.data.frame), names_to = "name")

  name X[[i]]
1    a      1
2    a      2
3    b      3
4    b      4
5    b      5
6    b      6
7    b      7

There is of course the drawback of changing every vector to a data.frame first and then binding them, but maybe it's still okay for you?

1 Like

This just needs generalization to seq_along(d)

d <- list(a = 1:2, b = 3:7)
f <- data.frame(name = as.character(), value = as.integer())

shimmy <- function(x) {
  a = expand.grid(d[x])
  colnames(a) = "value"
  a$names = names(expand.grid(d[x]))
  return(a[2:1])
}
 
rbind(f,shimmy(1),shimmy(2))
#>   names value
#> 1     a     1
#> 2     a     2
#> 3     b     3
#> 4     b     4
#> 5     b     5
#> 6     b     6
#> 7     b     7

Created on 2023-02-19 with reprex v2.0.2

Hi Courtiol,

I've needed to do this before and arrived at this solution:

d <- list(a = 1:2, b = 3:7)

map(d, ~as.data.frame(.x)) %>% 
  bind_rows(., .id = "a_name")

The pipe and . pulls the two dataframes into the bind_rows function.

I typically use tibble::enframe for this, and then unnest using tidyr::unnest:

library(tidyr)
library(tibble)

d <- list(a = 1:2, b = 3:7)

tibble::enframe(d) %>% 
  tidyr::unnest(value)
#> # A tibble: 7 × 2
#>   name  value
#>   <chr> <int>
#> 1 a         1
#> 2 a         2
#> 3 b         3
#> 4 b         4
#> 5 b         5
#> 6 b         6
#> 7 b         7

Created on 2023-02-19 with reprex v2.0.2

2 Likes

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.