app - R: copiar/mover un entorno a otro
sidebarpanel shiny (6)
El método de "clonación" publicado por Tommy no realizará una clonación verdadera (profunda) cuando e1
contenga nombres que hagan referencia a otros entornos. Por ejemplo, si e1$nestedEnv
referencia a un entorno, e2$nestedEnv
hará referencia al mismo entorno, no a una copia de ese entorno. Por lo tanto, el nombre e1$nestedEnv$bar
hará referencia a la misma ubicación de memoria que e2$nestedEnv$bar
y cualquier nuevo valor asignado a e1$nestedEnv$bar
también se reflejará para e2$nestedEnv$bar
también. Este puede ser un comportamiento deseable, pero llamar a e2
un clon de e1
podría ser engañoso.
Aquí hay una función que le permitirá al usuario hacer una copia de un entorno mientras también copia cualquier entorno anidado (un "clon profundo", usando deep = TRUE
), o simplemente usa el método propuesto por Tommy para copiar el entorno mientras mantiene Referencias originales a cualquier entorno anidado (usando deep = FALSE
).
El método ''deep = TRUE'' usa rapply
para llamar de forma recursiva cloneEnv
en un entorno anidado dentro del envir
, para tantos niveles como los entornos estén anidados. Así que, al final, recursivamente se llama rapply
, lo cual es un poco rapply
, pero funciona bastante bien.
Tenga en cuenta que si un entorno anidado contiene un nombre que hace referencia a un entorno principal, el uso del método "profundo" nunca regresará de las llamadas recursivas. Si hubiera podido encontrar una manera de verificar esto, lo habría incluido ...
Tenga en cuenta, también, que los entornos pueden tener atributos, por lo que la copia de los atributos sería necesaria para un verdadero clon, que esta solución también aborda.
cloneEnv <- function(envir, deep = T) {
if(deep) {
clone <- list2env(rapply(as.list(envir, all.names = TRUE), cloneEnv, classes = "environment", how = "replace"), parent = parent.env(envir))
} else {
clone <- list2env(as.list(envir, all.names = TRUE), parent = parent.env(envir))
}
attributes(clone) <- attributes(envir)
return(clone)
}
Un ejemplo:
Cree el entorno e1
, que también contiene un entorno anidado:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Mostrar los valores para foo
y bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Haga un clon profundo (es decir, e2
contiene hace una copia de nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
en e1
referencia a un entorno de diferencia que nestedEnv
en e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
Pero los valores son los mismos porque e2$nestedEnv
es una copia de e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Cambia los valores en e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Y los valores en e1
permanecen sin cambios, de nuevo, porque e1$nestedEnv
apunta a un entorno diferente que e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Ahora, vuelva a crear e1
utilizando el método de Tommy:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
en e2
apunta al mismo entorno que nestedEnv
en e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Actualice los valores en e2
y nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Los valores de foo
son independientes:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
pero al actualizar el valor, la bar
e2
también ha actualizado la bar
e1$nestedEnv
porque e1$nestedEnv
y e2$nestedEnv
referencia al mismo entorno.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
Me gustaría preguntar si es posible copiar / mover todos los objetos de un entorno a otro, a la vez. Por ejemplo:
f1 <- function() {
print(v1)
print(v2)
}
f2 <- function() {
v1 <- 1
v2 <- 2
# environment(f1)$v1 <- v1 # It works
# environment(f1)$v2 <- v2 # It works
environment(f1) <- environment(f2) # It does not work
}
f2()
f1()
TNX, por adelantado
Para hacerlo:
environment(f1) <- environment(f2) # It does not work
Abra el entorno f1
y ejecute esto:
ls(load(f2))
Parece que hay al menos 3 cosas diferentes que puedes hacer:
- Clonar un entorno (crear un duplicado exacto)
- Copia el contenido de un entorno a otro.
- Comparte el mismo ambiente
Para clonar:
# Make the source env
e1 <- new.env()
e1$foo <- 1
e1$.bar <- 2 # a hidden name
ls(e1) # only shows "foo"
# This will clone e1
e2 <- as.environment(as.list(e1, all.names=TRUE))
# Check it...
identical(e1, e2) # FALSE
e2$foo
e2$.bar
Para copiar el contenido, puedes hacer lo que mostró @gsk. Pero de nuevo, la bandera all.names
es útil:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
Compartir el ambiente es lo que hizo @koshke. Esto es probablemente a menudo mucho más útil. El resultado es el mismo que si se creara una función local:
f2 <- function() {
v1 <- 1
v2 <- 2
# This local function has access to v1 and v2
flocal <- function() {
print(v1)
print(v2)
}
return(flocal)
}
f1 <- f2()
f1() # prints 1 and 2
Podrías usar asignar:
f1 <- function() {
print(v1)
print(v2)
}
f2 <- function() {
v1 <- 1
v2 <- 2
for(obj in c("v1","v2")) {
assign(obj,get(obj),envir=f1.env)
}
}
Si no desea enumerar los objetos, ls()
toma un argumento de entorno.
Y tendrás que descubrir cómo conseguir que f1.env sea un entorno que apunte dentro de f1 :-)
Prueba esto:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
Utilizo esta función en mi paquete para copiar objetos:
copyEnv <- function(from, to, names=ls(from, all.names=TRUE)) {
mapply(assign, names, mget(names, from), list(to),
SIMPLIFY = FALSE, USE.NAMES = FALSE)
invisible(NULL)
}