Suppose that I have a nested list like the following
test <- list(
a = data.frame(x = 1),
b = "foo",
c = list(
d = 1:5,
e = data.frame(y = 1),
f = "a",
list(g = "hello")
)
)
test
#> $a
#> x
#> 1 1
#>
#> $b
#> [1] "foo"
#>
#> $c
#> $c$d
#> [1] 1 2 3 4 5
#>
#> $c$e
#> y
#> 1 1
#>
#> $c$f
#> [1] "a"
#>
#> $c[[4]]
#> $c[[4]]$g
#> [1] "hello"
I want to know the location of character elements in this nested list. In this
case, I want to return a named vector or a named list with TRUE
if the element
is a character and FALSE
otherwise.
I can do that with rapply
, that unlists everything:
rapply(test, is.character)
#> a.x b c.d c.e.y c.f c.g
#> FALSE TRUE FALSE FALSE TRUE TRUE
However, I can’t do that to find all dataframes because rapply()
also unlists
dataframes (note that the first element is a.x
and not only a
).
rapply(test, is.data.frame)
#> a.x b c.d c.e.y c.f c.g
#> FALSE FALSE FALSE FALSE FALSE FALSE
Therefore, is there a way to find which elements of a nested list are dataframes? Note that the solution should work with any number of levels in the nested list.
I’m looking for a solution in base R only.
CodePudding user response:
1) rrapply
library(rrapply)
cls <- c("data.frame", "ANY")
rrapply(test, f = is.data.frame, classes = cls, how = "unlist")
## a b c.d c.e c.f c.g
## TRUE FALSE FALSE TRUE FALSE FALSE
2) recursion
findDF <- function(x) {
if (is.data.frame(x)) TRUE
else if (is.list(x)) lapply(x, findDF)
else FALSE
}
unlist(findDF(test))
## a b c.d c.e c.f c.g
## TRUE FALSE FALSE TRUE FALSE FALSE