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