Create list of lists from tibble
Asked Answered
E

4

6

I'm trying to do something that seems very simple, but I cannot figure it out. I have a tibble like so:

> df <- tibble::tribble(
  ~col_a, ~col_b,
  1,      "A",   
  2,      "B",   
  3,      "C",   
)
> df
# # A tibble: 3 x 2
# col_a col_b
# <dbl> <chr>
#   1     A    
#   2     B    
#   3     C 

and I want to turn it into a list that looks like this

> str(res_list)
# List of 3
# $ :List of 2
# ..$ col_a: num 1
# ..$ col_b: chr "A"
# $ :List of 2
# ..$ col_a: num 2
# ..$ col_b: chr "B"
# $ :List of 2
# ..$ col_a: num 3
# ..$ col_b: chr "C"

I tried a number of things using base apply and dplyr::rowwise but nothing worked quite right. In the docs for purrr::pmap I thought I found the answer:

f.   A function, formula, or vector (not necessarily atomic)...

If character vector, numeric vector, or list, it is converted to an extractor function. Character vectors index by name...

So I thought, great this should work: pmap(df, c("col_a", "col_b")) and that should extract those columns for each element (row) and return a list of the extracted lists. But when I run that I get:

 Error in pluck(x, "col_a", "col_b", .default = NULL) : 
  argument "x" is missing, with no default 

I semi-understand this error, but I think I'm following the usage in the docs. Maybe this is just a bug in purrr?

Anyway, commentary on the potential purrr bug is welcome, but really I'm just trying to create this list. Any help is very appreciated.

Eduard answered 24/7, 2020 at 14:33 Comment(1)
Regarding the issue you had with apply: #29187925, #2392716Cambium
H
5

You can use group_split() (or base split() if you prefer):

library(dplyr)
library(purrr)

df %>%
  group_split(row_number(), .keep = FALSE) %>%
  map(as.list)

Where str() gives:

List of 3
 $ :List of 2
  ..$ col_a: num 1
  ..$ col_b: chr "A"
 $ :List of 2
  ..$ col_a: num 2
  ..$ col_b: chr "B"
 $ :List of 2
  ..$ col_a: num 3
  ..$ col_b: chr "C"

Or:

lapply(split(df, 1:nrow(df)),
       as.list)
Houck answered 24/7, 2020 at 14:38 Comment(1)
Perfect! Thank you. I had not considered group_split() by row number. This feels very like SQL for some reason. The lapply option works too, but it names each element of the list with the row number, which might be fine but is a little less clean. Thank you!Eduard
P
5

You can use asplit():

type.convert(lapply(asplit(df, 1), as.list), as.is = TRUE)

or by()

`attributes<-`(by(df, 1:nrow(df), as.list), NULL)

Both of str() give

List of 3
 $ :List of 2
  ..$ col_a: int 1
  ..$ col_b: chr "A"
 $ :List of 2
  ..$ col_a: int 2
  ..$ col_b: chr "B"
 $ :List of 2
  ..$ col_a: int 3
  ..$ col_b: chr "C"
Pacien answered 24/7, 2020 at 14:56 Comment(3)
This looks good on the surface, but note the comment on another answer (although now I see that answer is deleted, so please don't delete this answer) that points out how lapply mysteriously converts everything to a character vector. This is especially bad if your real tibble is more complex than the one in the example.Eduard
@Eduard Fixed. please check.Pacien
Yes, those both work too. Thank you for the update.Eduard
D
4

We can use pmap

library(purrr)
dflist <- df %>%
              pmap(~ list(...))
str(dflist)
#List of 3
# $ :List of 2
#  ..$ col_a: num 1
#  ..$ col_b: chr "A"
# $ :List of 2
#  ..$ col_a: num 2
#  ..$ col_b: chr "B"
# $ :List of 2
#  ..$ col_a: num 3
#  ..$ col_b: chr "C"
Dingo answered 24/7, 2020 at 21:54 Comment(0)
F
0

You can use slider:

install.packages("slider")
library(slider)
slide(df,~as.list(.x))
str(slide(df,~as.list(.x)))
Faught answered 5/4 at 4:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.