Reputation: 1830
I would like to subset an environment by its variable names.
e <- new.env(parent=emptyenv())
e$a <- 1
e$b <- 2
e$d <- 3
e[ls(e) %in% c("a","b", "c")]
### if e was a list, this would return the subset list(a=1, b=2)
I could not figure out how to subset elements of an environment by their names. Using lapply or eapply does not work either. What is the proper or easy way to subset an environment by its variable names? Thank you.
Upvotes: 4
Views: 2553
Reputation: 66
You can use rlang::env_get_list() to get a list of the bindings:
rlang::env_get_list(env=e, c("a","b"))
#$a
#[1] 1
#
#$b
#[1] 2
If you're trying to get an environment, rather than a list, I'm not sure how you would do that, other than just creating a new environment using the output of rlang::env_get_list().
If you want to include elements in your list that might not exist in the environment (like "c"), you have to specify a default value - otherwise you'll get an error:
env_get_list(env = e, c("a","b","c"))
#Error in env_get_list(env = e, c("a", "b", "c")) : argument "default" is missing, with no default
env_get_list(env = e, c("a","b","c"),default=NULL)
#$a
#[1] 1
#
#$b
#[1] 2
#
#$c
#NULL
I assume you don't want c at all, so I'd do something like:
temp <- c("a","b","c")[c("a","b","c") %in% env_names(e)]
temp
[1] "a" "b"
env_get_list(env=e,temp)
#$a
#[1] 1
#
#$b
#[1] 2
Upvotes: 2
Reputation: 46876
The [
operator usually returns the same type of object as the original, so I guess you're expecting an environment, rather than a list. The same environment but with a different set of elements, or a new environment with the specified elements? Either way I think you'll end up iterating, e.g.,
f = new.env(parent=emptyenv())
for (elt in c("a", "b"))
f[[elt]] = e[[elt]]
Working with environments is not very idiomatic R code, which might explain why there is not a more elegant solution.
Upvotes: 2
Reputation: 73385
My original solution is to use get()
/ mget()
(maybe OP saw my deleted comment earlier). Then I noticed that OP had tried eapply()
, so I thought about possible solutions with that. Here it is (with help of @thelatemail).
# try some different data type
e <- new.env(parent=emptyenv())
e$a <- 1:3
e$b <- matrix(1:4, 2)
e$c <- data.frame(x=letters[1:2],y=LETTERS[1:2])
You can use either of the following to collect objects in environment e
into a list:
elst <- eapply(e, "[") ## my idea
elst <- eapply(e, identity) ## thanks to @thelatemail
elst <- as.list.environment(e) ## thanks to @thelatemail
#$a
#[1] 1 2 3
#$b
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
#$c
# x y
#1 a A
#2 b B
The as.list.environment()
can be seen as the inverse operation of list2env()
. It is mentioned in the "See Also" part of ?list2env
.
The result elst
is just an ordinary list. There are various way to subset this list. For example:
elst[names(elst) %in% c("a","b")] ## no need to use "ls(e)" now
#$a
#[1] 1 2 3
#$b
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
Upvotes: 3
Reputation: 93938
Okay, after thinking this through a bit more, may I suggest:
mget(c("a","b"), envir=e)
#$a
#[1] 1
#
#$b
#[1] 2
Upvotes: 7