Home > front end >  How to pull out an element of a nested list in R that corresponds to the name of an entry?
How to pull out an element of a nested list in R that corresponds to the name of an entry?

Time:11-09

I have nested set of lists that looks like

Example_List = list(Object=list(list(name="A",value=0.1),list(name="B",value=0.5),list(name="C",value=2)))

> Example_List
$Object
$Object[[1]]
$Object[[1]]$name
[1] "A"

$Object[[1]]$value
[1] 0.1


$Object[[2]]
$Object[[2]]$name
[1] "B"

$Object[[2]]$value
[1] 0.5


$Object[[3]]
$Object[[3]]$name
[1] "C"

$Object[[3]]$value
[1] 2

I would like to retrieve the value in the list of lists that corresponds to a given name. For example, if it was name="B", the value to retrieve would be 0.5. One way to do this is to search for the name index by using multiple lapply functions, then use that index (2) to retrieve the value.

Is there a more elegant solution in R?

CodePudding user response:

There are probably simpler ways of solving this but the recursive function below does the job.
This post may also be useful.

Example_List = list(Object=list(list(name="A",value=0.1),
                                list(name="B",value=0.5),
                                list(name="C",value=2)))


find <- function(L, name) {
  if(is.list(L)) {
    if(any(names(L) == 'name')) {
      if(L[['name']] == name) {
        return(L[['value']])
      } else NULL
    } else {
      for(ll in L) {
        out <- Recall(ll, name)
        if(!is.null(out)) return(out)
      }
    }
  } else L
}
find(Example_List, 'A')
#> [1] 0.1
find(Example_List, 'B')
#> [1] 0.5
find(Example_List, 'C')
#> [1] 2

# this one doesn't exist in the list
f <- find(Example_List, 'X')
print(f)
#> NULL

Created on 2022-11-08 with reprex v2.0.2

CodePudding user response:

How about this?

xy <- sapply(Example_List[[1]], as.data.frame, simplify = FALSE)
xy <- do.call(rbind, xy)
xy
  name value
1    A   0.1
2    B   0.5
3    C   2.0

CodePudding user response:

Another approach is to first convert the nested list into a rectangular data.frame, after which filtering by name/value is easy. For instance,

## tidyverse
dplyr::bind_rows(Example_List[[1]])
#> # A tibble: 3 × 2
#>   name  value
#>   <chr> <dbl>
#> 1 A       0.1
#> 2 B       0.5
#> 3 C       2

## data.table
data.table::rbindlist(Example_List[[1]])
#>    name value
#> 1:    A   0.1
#> 2:    B   0.5
#> 3:    C   2.0

For deeper nested lists we can also use rrapply():

rrapply::rrapply(Example_List, how = "bind")
#>   name value
#> 1    A   0.1
#> 2    B   0.5
#> 3    C   2.0

To filter values by name would then simply be a matter of e.g.:

library(dplyr)

bind_rows(Example_List[[1]]) |>
  filter(name == "A")
#> # A tibble: 1 × 2
#>   name  value
#>   <chr> <dbl>
#> 1 A       0.1
  •  Tags:  
  • r
  • Related