R: как вы объедините/объедините две среды?

Это простой вопрос, но ответ, по-видимому, не так прост... Возможно ли комбинировать среды в R?

E1 = new.env()
E2 = new.env()
E1$x = 25
E2$y = 7

Хорошо, теперь мне нужна среда (скажем, E3), которая имеет как x, так и y.

c(E1, E2)
#doesn't work
E3 = new.env(E1, E2)
#doesn't work

Я нашел другие подобные вопросы, но они, похоже, не работают для меня.

Случай использования: Возможно, причина в том, что это непросто... Причина, по которой я хочу это сделать, заключается в следующем: я использую некоторые функции для загрузки данных. Раньше я только что загрузил его в глобальную среду, но теперь у меня много разных функций, загружающих разные типы данных (которые я называю по-разному по мере необходимости), и поэтому я хотел сохранить загруженные данные немного более разделенными. Если я вызываю две разные функции загрузки E1=loadData1() и E2=loadData2(), и теперь я хочу вызвать функцию, которая использует переменные из обеих этих функций, я бы хотел сказать with(E1 & E2, someFunction()). Следовательно, слияние моих загруженных сред кажется подходящим.

Итак, каков правильный способ их слияния? И, как в стороне, есть ли у вас другое предложение о том, как лучше выполнить то, что я делаю, если слияние сред не подходит?

Ответ 1

1 Сделайте одну среду родительской для другой и используйте with(child, ...):

parent <- new.env(); parent$x <- 1
child <- new.env(parent = parent); child$y <- 2

with(child, x + y) # x comes from child and y from parent
## [1] 3

Вы можете связать столько окружений, сколько хотите, по мере необходимости, цепочкой.

Обратите внимание, что если ребенок изначально был создан без родителя, вы можете добавить родителя позже, используя:

parent.env(child) <- parent

Таким образом, мы определяем LoadData1 и LoadData2 как:

# define LoadData1 to have a parent argument
LoadData1 <- function(parent = emptyenv()) {
        # calculation of environment e goes here
        parent.env(e) <- parent
        e
}

# define LoadData2 to have a parent argument
LoadData2 <- function(parent = emptyenv()) {
        # calculation of environment e goes here
        parent.env(e) <- parent
        e
}

# run
e1 <- LoadData1()
e2 <- LoadData2(parent = e1)
with(e2, dataFrom1 + dataFrom2)

Если вы не хотите изменять LoadData1 и LoadData2 из того, что они сейчас:

e1 <- LoadData1()
e2 <- LoadData2()
parent.env(e2) <- e1
with(e2, dataFrom1 + dataFrom2)

2 Преобразование в списки:

with(c(as.list(e1), as.list(e2)), somefunction())

ADDED Второй подход.

Ответ 2

Вы можете сделать это, объединив их, преобразуя среды в списки и затем переведя назад:

E3 <- as.environment(sapply(c(E1,E2),as.list))
ls(env=E3)
[1] "x" "y"
E3$x
[1] 25
E3$y
[1] 7

Ответ 3

Я сделал эту функцию:

> appendEnv = function(e1, e2) {
+     e1name = deparse(substitute(e1))
+     e2name = deparse(substitute(e2))
+     listE1 = ls(e1)
+     listE2 = ls(e2)
+     for(v in listE2) {
+         if(v %in% listE1) warning(sprintf("Variable %s is in e1, too!", v))
+         e1[[v]] = e2[[v]]
+     }
+ }

> e1 = new.env()
> e2 = new.env()
> e1$x = 1
> e1$y = 2
> e2$y = 3
> e2$z = 4
> appendEnv(e1, e2)
Warning message:
In appendEnv(e1, e2) : Variable y is in e1, too!
> as.list(e1)
$x
[1] 1

$y
[1] 3

$z
[1] 4