sidebarpanel app r

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:

  1. Clonar un entorno (crear un duplicado exacto)
  2. Copia el contenido de un entorno a otro.
  3. 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) }