Is there a straightforward, pipe-friendly way to generate a list
object from a tibble that contains list-columns?
Consider the example below. If my_starwars
is a given tibble, how can I achieve a named list like desired_output
?
library(dplyr, warn.conflicts = FALSE)
library(purrr)
my_starwars <-
starwars %>%
slice(1)
films <- my_starwars %>% pull(films) %>% set_names("films")
vehicles <- my_starwars %>% pull(vehicles) %>% set_names("vehicles")
desired_output <- c(films, vehicles)
desired_output
#> $films
#> [1] "The Empire Strikes Back" "Revenge of the Sith"
#> [3] "Return of the Jedi" "A New Hope"
#> [5] "The Force Awakens"
#>
#> $vehicles
#> [1] "Snowspeeder" "Imperial Speeder Bike"
Although the code above does the job, I want something less manual that can stem from the pipe, such as:
my_starwars %>%
build_list(films, vehicles, foo, bar) # this is a demo
## $films
## [1] "The Empire Strikes Back" "Revenge of the Sith" "Return of the Jedi" "A New Hope" ## "The Force Awakens"
## $vehicles
## [1] "Snowspeeder" "Imperial Speeder Bike"
## $foo
## [1] "foo" "foo" "foo"
## $bar
## [1] "bar" "bar"
Is there a straightforward way to do this with tidyverse
tools?
EDIT
Although the solution by @GuedesBF is great for the initial my_starwars
example, it fails with a different type of tibble. So my original example was too minimal and not representative of my issue. Please consider the following example, in which trb
is a tibble that holds 2 list-columns, with a recipe
object in each.
library(recipes)
car_rec_1 <-
recipe(mpg ~ ., data = mtcars) %>%
step_ns(disp, deg_free = 5)
car_rec_2 <-
recipe(mpg ~ ., data = mtcars) %>%
step_dummy(am)
trb <-
tribble(~car_rec_1, ~car_rec_2,
car_rec_1, car_rec_2)
undesired_output_trb <-
trb %>%
lapply(unlist)
car_rec_1 <- trb %>% pull(car_rec_1) %>% setNames("car_rec_1")
car_rec_2 <- trb %>% pull(car_rec_2) %>% setNames("car_rec_2")
desired_output_trb <- c(car_rec_1, car_rec_2)
When we use @GuedesBF's solution we get the undesired_output_trb
, whereas what I want is desired_output_trb
. How can this be achieved?
CodePudding user response:
We can loop-apply a function to unlist()
the select
ed columns.
my_starwars %>%
select(c(films, vehicles)) %>%
lapply(unlist)
#Or if tidyverse is a must, we can replace `lapply` with `purrr::map`
my_starwars %>%
select(c(films, vehicles)) %>%
map(unlist)
$films
[1] "The Empire Strikes Back" "Revenge of the Sith" "Return of the Jedi" "A New Hope" "The Force Awakens"
$vehicles
[1] "Snowspeeder" "Imperial Speeder Bike"
Update
The second example given by the OP contains nested lists, list columns with list elements inside. The simpler lapply(unlist)
or unclass()
solutions wont work here. We need an unlisting function that provides exra control, for which i would recommend purrr::pluck
. map(my_starwars, pluck, 1)
works for the original question too.
library(purrr)
trb %>%
map(pluck, 1)
identical(desired_output_trb, trb %>% map(pluck, 1))
[1] TRUE
CodePudding user response:
Based on this answer, another solution would be with tidyr::pivot_longer()
and tibble::deframe()
:
library(dplyr, warn.conflicts = FALSE)
library(tibble)
library(tidyr)
my_starwars <-
starwars %>%
slice(1)
my_starwars %>%
select(films, vehicles) %>%
pivot_longer(everything()) %>%
deframe()
#> $films
#> [1] "The Empire Strikes Back" "Revenge of the Sith"
#> [3] "Return of the Jedi" "A New Hope"
#> [5] "The Force Awakens"
#>
#> $vehicles
#> [1] "Snowspeeder" "Imperial Speeder Bike"
library(recipes)
car_rec_1 <-
recipe(mpg ~ ., data = mtcars) %>%
step_ns(disp, deg_free = 5)
car_rec_2 <-
recipe(mpg ~ ., data = mtcars) %>%
step_dummy(am)
trb <-
tribble(~car_rec_1, ~car_rec_2,
car_rec_1, car_rec_2)
trb %>%
pivot_longer(everything()) %>%
deframe()
#> $car_rec_1
#> Recipe
#>
#> Inputs:
#>
#> role #variables
#> outcome 1
#> predictor 10
#>
#> Operations:
#>
#> Natural Splines on disp
#>
#> $car_rec_2
#> Recipe
#>
#> Inputs:
#>
#> role #variables
#> outcome 1
#> predictor 10
#>
#> Operations:
#>
#> Dummy variables from am