Home > Blockchain >  How to build a named list from tibble list columns?
How to build a named list from tibble list columns?

Time:12-31

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 selected 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
  • Related