Reputation: 13070
I really think I'm missing something totally obvious here, but I just can't put my finger on it: how can I combine rapply()
and either as.list()
or eapply()
or both in order to recursively convert a nested environment
into a nested list
.
What I'm actually after is something like as.list(<env>, recursive=TRUE)
and I thought that rapply()
would somehow be usefull in this.
That's the nested environment:
env <- new.env()
env$world <- new.env()
env$world$europe <- new.env()
env$world$europe$germany <- new.env()
env$world$europe$germany$foo <- 1
env$world$europe$germany$bar <- 2
That's the structrue I'd like to end up with:
env.as.list <- list(
world=list(europe=list(germany=list(foo=1, bar=2)))
)
> env.as.list
$world
$world$europe
$world$europe$germany
$world$europe$germany$foo
[1] 1
$world$europe$germany$bar
[1] 2
And rather than building some slow recursive function based on lapply()
, I would like to make use of the fast .Internal()
function in rapply()
.
But as rapply
is meant to work on lists
, of course it will "stop" once it hits an environment
:
> rapply(as.list(env), as.list, how="list")
$world
$world$europe
<environment: 0x000000001748d640>
What's the trick here?
Upvotes: 0
Views: 170
Reputation: 9344
rapply
is only for nested lists; use recursion.
nested_env_list <- function(env) {
out <- as.list(env)
lapply(out, function(x) if (is.environment(x)) nested_env_list(x) else x)
}
Example:
> env <- new.env(); env$a <- new.env(); env$a$b <- 1; env$a$c <- 2; env$d <- 4
> dput(nested_env_list(env))
structure(list(a = structure(list(b = 1, c = 2), .Names = c("b", "c")), d = 4), .Names = c("a", "d"))
as.list
:You can also replace the behavior of as.list
to ensure this happens throughout whenever you pass an environment to as.list
.
as.list.environment <- function(env) {
out <- base::as.list.environment(env)
lapply(out, function(x) if (is.environment(x)) as.list(x) else x)
}
Then R will figure it out automatically for all future environments. If you want the old behavior in a few select places, use base::as.list.environment
explicitly.
Example:
> env <- new.env(); env$a <- new.env(); env$a$b <- 1; env$a$c <- 2; env$d <- 4
> dput(as.list(env))
structure(list(a = structure(list(b = 1, c = 2), .Names = c("b", "c")), d = 4), .Names = c("a", "d"))
Finally, you should ask yourself why you get infinite recursion if you replace out <- base::as.list.environment(env)
above with out <- base::as.list(env)
.
Upvotes: 4