ℕʘʘḆḽḘ
ℕʘʘḆḽḘ

Reputation: 19405

extracting data from deeply nested list

Consider this convoluted and nested example (which, believe it or not arises for real in my dataset)

> nestedlist <- list(list('fakedata' = 'hello',
+                    list(list('name'= list('john','litz'), 'age'= 30))),
+                    list('fakedata' = 'there',
+                    list(list('name'= list('frank','doe'), 'age'= 34))))
> 
> nestedlist %>% str
List of 2
 $ :List of 2
  ..$ fakedata: chr "hello"
  ..$         :List of 1
  .. ..$ :List of 2
  .. .. ..$ name:List of 2
  .. .. .. ..$ : chr "john"
  .. .. .. ..$ : chr "litz"
  .. .. ..$ age : num 30
 $ :List of 2
  ..$ fakedata: chr "there"
  ..$         :List of 1
  .. ..$ :List of 2
  .. .. ..$ name:List of 2
  .. .. .. ..$ : chr "frank"
  .. .. .. ..$ : chr "doe"
  .. .. ..$ age : num 34

I am trying to use purrr to extract elements from it. Something simple like extracting the fakedata field works easily:

> purrr::map(nestedlist, 'fakedata')
[[1]]
[1] "hello"

[[2]]
[1] "there"

However, I am interested in the name field. And in this case my purrr solution does not work:

> purrr::map(nestedlist, list(1,1,'name')) 
[[1]]
NULL

[[2]]
NULL

What is the issue here? Thanks!

Upvotes: 4

Views: 523

Answers (2)

Joris C.
Joris C.

Reputation: 6244

Another option is to use rrapply() in the rrapply-package (an extension of base rapply()), which is made exactly for this purpose:

library(rrapply)   ## v1.2.1

## filter 'name' nodes as flat list
str(rrapply(nestedlist, classes = "list", condition = function(x, .xname) .xname == "name", how = "flatten"))
#> List of 2
#>  $ name:List of 2
#>   ..$ : chr "john"
#>   ..$ : chr "litz"
#>  $ name:List of 2
#>   ..$ : chr "frank"
#>   ..$ : chr "doe"


## prune 'name' nodes maintaining list structure
str(rrapply(nestedlist, classes = "list", condition = function(x, .xname) .xname == "name", how = "prune"))
#> List of 2
#>  $ :List of 1
#>   ..$ :List of 1
#>   .. ..$ :List of 1
#>   .. .. ..$ name:List of 2
#>   .. .. .. ..$ : chr "john"
#>   .. .. .. ..$ : chr "litz"
#>  $ :List of 1
#>   ..$ :List of 1
#>   .. ..$ :List of 1
#>   .. .. ..$ name:List of 2
#>   .. .. .. ..$ : chr "frank"
#>   .. .. .. ..$ : chr "doe"

Upvotes: 1

Greg Foletta
Greg Foletta

Reputation: 36

I was going to suggest the use of purrr::pluck(), then then reading through the doco I discovered you could actually just use a purrr::map().

You're very close: you need to pass a list of accessors to map() rather than a character vector, and there's an accessor you've missed.

nestedlist %>% map( list('data', 1, 'name') )

[[1]]
[[1]][[1]]
[1] "john"

[[1]][[2]]
[1] "litz"


[[2]]
[[2]][[1]]
[1] "frank"

[[2]][[2]]
[1] "doe"

Upvotes: 1

Related Questions