R: copy/move one environment to another
I would like to ask if it is possible to copy/move all the objects of one environment to another, at once. For example:
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, in advance
r
add a comment |
I would like to ask if it is possible to copy/move all the objects of one environment to another, at once. For example:
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, in advance
r
add a comment |
I would like to ask if it is possible to copy/move all the objects of one environment to another, at once. For example:
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, in advance
r
I would like to ask if it is possible to copy/move all the objects of one environment to another, at once. For example:
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, in advance
r
r
edited Apr 1 '12 at 15:33
Apostolos Polymeros
asked Apr 1 '12 at 15:23
Apostolos PolymerosApostolos Polymeros
418617
418617
add a comment |
add a comment |
6 Answers
6
active
oldest
votes
There seem to be at least 3 different things you can do:
- Clone an environment (create an exact duplicate)
- Copy the content of one environment to another environment
- Share the same environment
To clone:
# 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
To copy the content, you can do what @gsk showed. But again, the all.names
flag is useful:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
To share the environment is what @koshke did. This is probably often much more useful. The result is the same as if creating a local function:
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
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
add a comment |
Try this:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
add a comment |
You could use assign:
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)
}
}
If you don't want to list out the objects, ls()
takes an environment argument.
And you'll have to figure out how to get f1.env to be an environment pointing inside f1 :-)
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigningv1
andv2
into.GlovalEnv
...
– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the,envir
option doesn't do what I thought it did. I'll look further.
– Ari B. Friedman
Apr 1 '12 at 15:47
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
|
show 2 more comments
I use this function in my package to copy objects:
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)
}
add a comment |
To do it:
environment(f1) <- environment(f2) # It does not work
Open the f1
environment and run do this:
ls(load(f2))
add a comment |
The "clone" method posted by Tommy won't make a true (deep) clone when e1
contains names that reference other environments. For instance, if e1$nestedEnv
references an environment, e2$nestedEnv
will reference the same environment, not a copy of that environment. Thus, the name e1$nestedEnv$bar
will reference the same memory location as e2$nestedEnv$bar
and any new value assigned to e1$nestedEnv$bar
will be reflected for e2$nestedEnv$bar
as well. This may be desirable behavior, but calling e2
a clone of e1
could be misleading.
Here is a function that will allow the user to make either a copy of an environment while also copying any nested environments (a "deep clone", using deep = TRUE
), or just use the method proposed by Tommy to copy the environment while maintaining original references to any nested environments (using deep = FALSE
).
The 'deep = TRUE' method uses rapply
to recursively call cloneEnv
on nested environment within envir
, for as many levels as the environments are nested. So, in the end, it recursively calls rapply
, which is a bit of a mind bender, but works pretty well.
Note that if a nested environment contains a name that references a parent environment, using the "deep" method will never return from the recursive calls. If I could have figured out a way to check for this, I would have included it...
Note, too, that environments can have attributes, so copying the attributes would be necessary for a true clone, which this solution also addresses.
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)
}
An example:
Create environment e1
, which also contains a nested environment:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Show the values for foo
and bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Make a deep clone (i.e. e2
contains makes a copy of nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
references a difference environment than nestedEnv
in e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
But the values are the same because e2$nestedEnv
is a copy of e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Change the values in e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
And values in e1
remain unchanged, again, because e1$nestedEnv
points to a different environment than e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Now, re-create e1
using Tommy's method:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
in e2
points to the same environment as nestedEnv
in e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Update the values in e2
and e2
's nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Values of foo
are independent:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
but updating value e2
's bar
has also updated e1
's bar
because e1$nestedEnv
and e2$nestedEnv
reference (point to) the same environment.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f9965577%2fr-copy-move-one-environment-to-another%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
There seem to be at least 3 different things you can do:
- Clone an environment (create an exact duplicate)
- Copy the content of one environment to another environment
- Share the same environment
To clone:
# 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
To copy the content, you can do what @gsk showed. But again, the all.names
flag is useful:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
To share the environment is what @koshke did. This is probably often much more useful. The result is the same as if creating a local function:
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
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
add a comment |
There seem to be at least 3 different things you can do:
- Clone an environment (create an exact duplicate)
- Copy the content of one environment to another environment
- Share the same environment
To clone:
# 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
To copy the content, you can do what @gsk showed. But again, the all.names
flag is useful:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
To share the environment is what @koshke did. This is probably often much more useful. The result is the same as if creating a local function:
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
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
add a comment |
There seem to be at least 3 different things you can do:
- Clone an environment (create an exact duplicate)
- Copy the content of one environment to another environment
- Share the same environment
To clone:
# 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
To copy the content, you can do what @gsk showed. But again, the all.names
flag is useful:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
To share the environment is what @koshke did. This is probably often much more useful. The result is the same as if creating a local function:
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
There seem to be at least 3 different things you can do:
- Clone an environment (create an exact duplicate)
- Copy the content of one environment to another environment
- Share the same environment
To clone:
# 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
To copy the content, you can do what @gsk showed. But again, the all.names
flag is useful:
# e1 is source env, e2 is dest env
for(n in ls(e1, all.names=TRUE)) assign(n, get(n, e1), e2)
To share the environment is what @koshke did. This is probably often much more useful. The result is the same as if creating a local function:
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
edited Apr 1 '12 at 17:49
answered Apr 1 '12 at 17:17
TommyTommy
31.7k87879
31.7k87879
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
add a comment |
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
it's a complete answer
– Apostolos Polymeros
Apr 1 '12 at 19:19
add a comment |
Try this:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
add a comment |
Try this:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
add a comment |
Try this:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
Try this:
f2 <- function() {
v1 <- 1
v2 <- 2
environment(f1) <<- environment()
}
answered Apr 1 '12 at 15:33
kohskekohske
52.6k6144146
52.6k6144146
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
add a comment |
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
You are right, thank you a lot !
– Apostolos Polymeros
Apr 1 '12 at 15:39
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
+1 - nice one...
– Tommy
Apr 1 '12 at 17:24
add a comment |
You could use assign:
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)
}
}
If you don't want to list out the objects, ls()
takes an environment argument.
And you'll have to figure out how to get f1.env to be an environment pointing inside f1 :-)
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigningv1
andv2
into.GlovalEnv
...
– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the,envir
option doesn't do what I thought it did. I'll look further.
– Ari B. Friedman
Apr 1 '12 at 15:47
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
|
show 2 more comments
You could use assign:
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)
}
}
If you don't want to list out the objects, ls()
takes an environment argument.
And you'll have to figure out how to get f1.env to be an environment pointing inside f1 :-)
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigningv1
andv2
into.GlovalEnv
...
– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the,envir
option doesn't do what I thought it did. I'll look further.
– Ari B. Friedman
Apr 1 '12 at 15:47
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
|
show 2 more comments
You could use assign:
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)
}
}
If you don't want to list out the objects, ls()
takes an environment argument.
And you'll have to figure out how to get f1.env to be an environment pointing inside f1 :-)
You could use assign:
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)
}
}
If you don't want to list out the objects, ls()
takes an environment argument.
And you'll have to figure out how to get f1.env to be an environment pointing inside f1 :-)
edited Apr 1 '12 at 16:15
answered Apr 1 '12 at 15:38
Ari B. FriedmanAri B. Friedman
47.4k26149210
47.4k26149210
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigningv1
andv2
into.GlovalEnv
...
– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the,envir
option doesn't do what I thought it did. I'll look further.
– Ari B. Friedman
Apr 1 '12 at 15:47
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
|
show 2 more comments
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigningv1
andv2
into.GlovalEnv
...
– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the,envir
option doesn't do what I thought it did. I'll look further.
– Ari B. Friedman
Apr 1 '12 at 15:47
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
It is a very good answer
– Apostolos Polymeros
Apr 1 '12 at 15:42
Note that this code simply assigning
v1
and v2
into .GlovalEnv
...– kohske
Apr 1 '12 at 15:44
Note that this code simply assigning
v1
and v2
into .GlovalEnv
...– kohske
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
Thanks! It was a fun question. @kohske's solution seems more elegant (as always!).
– Ari B. Friedman
Apr 1 '12 at 15:44
@kohske Uh oh. Maybe the
,envir
option doesn't do what I thought it did. I'll look further.– Ari B. Friedman
Apr 1 '12 at 15:47
@kohske Uh oh. Maybe the
,envir
option doesn't do what I thought it did. I'll look further.– Ari B. Friedman
Apr 1 '12 at 15:47
2
2
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
For what it's worth, this answer seems to match the way I've seen it done internally in R code written by R core members ... so it may be "canonical". @kohske's is cleverer, but that makes me nervous.
– Ben Bolker
Apr 1 '12 at 16:09
|
show 2 more comments
I use this function in my package to copy objects:
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)
}
add a comment |
I use this function in my package to copy objects:
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)
}
add a comment |
I use this function in my package to copy objects:
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)
}
I use this function in my package to copy objects:
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)
}
answered Nov 1 '15 at 17:38
Neal FultzNeal Fultz
7,3242438
7,3242438
add a comment |
add a comment |
To do it:
environment(f1) <- environment(f2) # It does not work
Open the f1
environment and run do this:
ls(load(f2))
add a comment |
To do it:
environment(f1) <- environment(f2) # It does not work
Open the f1
environment and run do this:
ls(load(f2))
add a comment |
To do it:
environment(f1) <- environment(f2) # It does not work
Open the f1
environment and run do this:
ls(load(f2))
To do it:
environment(f1) <- environment(f2) # It does not work
Open the f1
environment and run do this:
ls(load(f2))
edited May 27 '14 at 19:00
elimirks
1,24721529
1,24721529
answered May 27 '14 at 18:36
Brunno OliveiraBrunno Oliveira
163
163
add a comment |
add a comment |
The "clone" method posted by Tommy won't make a true (deep) clone when e1
contains names that reference other environments. For instance, if e1$nestedEnv
references an environment, e2$nestedEnv
will reference the same environment, not a copy of that environment. Thus, the name e1$nestedEnv$bar
will reference the same memory location as e2$nestedEnv$bar
and any new value assigned to e1$nestedEnv$bar
will be reflected for e2$nestedEnv$bar
as well. This may be desirable behavior, but calling e2
a clone of e1
could be misleading.
Here is a function that will allow the user to make either a copy of an environment while also copying any nested environments (a "deep clone", using deep = TRUE
), or just use the method proposed by Tommy to copy the environment while maintaining original references to any nested environments (using deep = FALSE
).
The 'deep = TRUE' method uses rapply
to recursively call cloneEnv
on nested environment within envir
, for as many levels as the environments are nested. So, in the end, it recursively calls rapply
, which is a bit of a mind bender, but works pretty well.
Note that if a nested environment contains a name that references a parent environment, using the "deep" method will never return from the recursive calls. If I could have figured out a way to check for this, I would have included it...
Note, too, that environments can have attributes, so copying the attributes would be necessary for a true clone, which this solution also addresses.
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)
}
An example:
Create environment e1
, which also contains a nested environment:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Show the values for foo
and bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Make a deep clone (i.e. e2
contains makes a copy of nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
references a difference environment than nestedEnv
in e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
But the values are the same because e2$nestedEnv
is a copy of e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Change the values in e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
And values in e1
remain unchanged, again, because e1$nestedEnv
points to a different environment than e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Now, re-create e1
using Tommy's method:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
in e2
points to the same environment as nestedEnv
in e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Update the values in e2
and e2
's nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Values of foo
are independent:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
but updating value e2
's bar
has also updated e1
's bar
because e1$nestedEnv
and e2$nestedEnv
reference (point to) the same environment.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
add a comment |
The "clone" method posted by Tommy won't make a true (deep) clone when e1
contains names that reference other environments. For instance, if e1$nestedEnv
references an environment, e2$nestedEnv
will reference the same environment, not a copy of that environment. Thus, the name e1$nestedEnv$bar
will reference the same memory location as e2$nestedEnv$bar
and any new value assigned to e1$nestedEnv$bar
will be reflected for e2$nestedEnv$bar
as well. This may be desirable behavior, but calling e2
a clone of e1
could be misleading.
Here is a function that will allow the user to make either a copy of an environment while also copying any nested environments (a "deep clone", using deep = TRUE
), or just use the method proposed by Tommy to copy the environment while maintaining original references to any nested environments (using deep = FALSE
).
The 'deep = TRUE' method uses rapply
to recursively call cloneEnv
on nested environment within envir
, for as many levels as the environments are nested. So, in the end, it recursively calls rapply
, which is a bit of a mind bender, but works pretty well.
Note that if a nested environment contains a name that references a parent environment, using the "deep" method will never return from the recursive calls. If I could have figured out a way to check for this, I would have included it...
Note, too, that environments can have attributes, so copying the attributes would be necessary for a true clone, which this solution also addresses.
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)
}
An example:
Create environment e1
, which also contains a nested environment:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Show the values for foo
and bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Make a deep clone (i.e. e2
contains makes a copy of nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
references a difference environment than nestedEnv
in e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
But the values are the same because e2$nestedEnv
is a copy of e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Change the values in e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
And values in e1
remain unchanged, again, because e1$nestedEnv
points to a different environment than e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Now, re-create e1
using Tommy's method:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
in e2
points to the same environment as nestedEnv
in e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Update the values in e2
and e2
's nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Values of foo
are independent:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
but updating value e2
's bar
has also updated e1
's bar
because e1$nestedEnv
and e2$nestedEnv
reference (point to) the same environment.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
add a comment |
The "clone" method posted by Tommy won't make a true (deep) clone when e1
contains names that reference other environments. For instance, if e1$nestedEnv
references an environment, e2$nestedEnv
will reference the same environment, not a copy of that environment. Thus, the name e1$nestedEnv$bar
will reference the same memory location as e2$nestedEnv$bar
and any new value assigned to e1$nestedEnv$bar
will be reflected for e2$nestedEnv$bar
as well. This may be desirable behavior, but calling e2
a clone of e1
could be misleading.
Here is a function that will allow the user to make either a copy of an environment while also copying any nested environments (a "deep clone", using deep = TRUE
), or just use the method proposed by Tommy to copy the environment while maintaining original references to any nested environments (using deep = FALSE
).
The 'deep = TRUE' method uses rapply
to recursively call cloneEnv
on nested environment within envir
, for as many levels as the environments are nested. So, in the end, it recursively calls rapply
, which is a bit of a mind bender, but works pretty well.
Note that if a nested environment contains a name that references a parent environment, using the "deep" method will never return from the recursive calls. If I could have figured out a way to check for this, I would have included it...
Note, too, that environments can have attributes, so copying the attributes would be necessary for a true clone, which this solution also addresses.
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)
}
An example:
Create environment e1
, which also contains a nested environment:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Show the values for foo
and bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Make a deep clone (i.e. e2
contains makes a copy of nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
references a difference environment than nestedEnv
in e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
But the values are the same because e2$nestedEnv
is a copy of e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Change the values in e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
And values in e1
remain unchanged, again, because e1$nestedEnv
points to a different environment than e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Now, re-create e1
using Tommy's method:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
in e2
points to the same environment as nestedEnv
in e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Update the values in e2
and e2
's nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Values of foo
are independent:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
but updating value e2
's bar
has also updated e1
's bar
because e1$nestedEnv
and e2$nestedEnv
reference (point to) the same environment.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
The "clone" method posted by Tommy won't make a true (deep) clone when e1
contains names that reference other environments. For instance, if e1$nestedEnv
references an environment, e2$nestedEnv
will reference the same environment, not a copy of that environment. Thus, the name e1$nestedEnv$bar
will reference the same memory location as e2$nestedEnv$bar
and any new value assigned to e1$nestedEnv$bar
will be reflected for e2$nestedEnv$bar
as well. This may be desirable behavior, but calling e2
a clone of e1
could be misleading.
Here is a function that will allow the user to make either a copy of an environment while also copying any nested environments (a "deep clone", using deep = TRUE
), or just use the method proposed by Tommy to copy the environment while maintaining original references to any nested environments (using deep = FALSE
).
The 'deep = TRUE' method uses rapply
to recursively call cloneEnv
on nested environment within envir
, for as many levels as the environments are nested. So, in the end, it recursively calls rapply
, which is a bit of a mind bender, but works pretty well.
Note that if a nested environment contains a name that references a parent environment, using the "deep" method will never return from the recursive calls. If I could have figured out a way to check for this, I would have included it...
Note, too, that environments can have attributes, so copying the attributes would be necessary for a true clone, which this solution also addresses.
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)
}
An example:
Create environment e1
, which also contains a nested environment:
e1 <- new.env()
e1$foo <- "Christmas"
e1$nestedEnv <- new.env()
e1$nestedEnv$bar <- "New Years"
Show the values for foo
and bar
:
e1$foo
[1] "Christmas"
e1$nestedEnv$bar
[1] "New Years"
Make a deep clone (i.e. e2
contains makes a copy of nestedEnv
)
e2 <- cloneEnv(e1, deep = TRUE)
nestedEnv
in e1
references a difference environment than nestedEnv
in e2
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] FALSE
But the values are the same because e2$nestedEnv
is a copy of e1$nestedEnv
:
e2$foo
[1] "Christmas"
e2$nestedEnv$bar
[1] "New Years"
Change the values in e2
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
And values in e1
remain unchanged, again, because e1$nestedEnv
points to a different environment than e2$nestedEnv
:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
e1$nestedEnv$bar
[1] "New Years"
e2$nestedEnv$bar
[1] "Thanksgiving"
Now, re-create e1
using Tommy's method:
e2 <- cloneEnv(e1, deep = FALSE)
nestedEnv
in e2
points to the same environment as nestedEnv
in e1
:
identical(e1$nestedEnv, e2$nestedEnv)
[1] TRUE
Update the values in e2
and e2
's nestedEnv
:
e2$foo <- "Halloween"
e2$nestedEnv$bar <- "Thanksgiving"
Values of foo
are independent:
e1$foo
[1] "Christmas"
e2$foo
[1] "Halloween"
but updating value e2
's bar
has also updated e1
's bar
because e1$nestedEnv
and e2$nestedEnv
reference (point to) the same environment.
e1$nestedEnv$bar
[1] "Thanksgiving"
e2$nestedEnv$bar
[1] "Thanksgiving"
edited Nov 13 '18 at 6:00
answered Nov 13 '18 at 5:40
Geoffrey PooleGeoffrey Poole
27126
27126
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f9965577%2fr-copy-move-one-environment-to-another%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown