Question:
I want to assign names to variables with a loop. for
I can:
library(tidyverse)
for(i in 1:6){
names<-str_c('var',i)
assign(names,runif(30,20,100))
}
But not with lapply
and map
:
lapply
lapply(1:6,function(i){
names<-str_c('var',i)
assign(names,runif(30,20,100))
})
map
map(1:6,function(i){
names<-str_c('var',i)
assign(names,runif(30,20,100))
})
Why does this occur? I write the same functions inside the blocks, but only outside the names for
assigned.
Answer:
This happens because assign
modifies the parent environment. In the case of for, the parent environment is the global environment itself. That's why the variables appear to you.
In the case of a function being called by map
or lapply
, the parent environment is the environment of the calling function itself, and this environment is destroyed shortly after the function is executed.
You can see the environment the function is using with the environment
function:
> for(i in 1:6){
+ names<-str_c('var',i)
+ print(environment())
+ assign(names,runif(30,20,100))
+ }
<environment: R_GlobalEnv>
<environment: R_GlobalEnv>
<environment: R_GlobalEnv>
<environment: R_GlobalEnv>
<environment: R_GlobalEnv>
<environment: R_GlobalEnv>
> lapply(1:6,function(i){
+ names<-str_c('var',i)
+ print(environment())
+ assign(names,runif(30,20,100))
+ })
<environment: 0x14eec3a0>
<environment: 0x2bd9e368>
<environment: 0x13b43ae0>
<environment: 0xe7213c0>
<environment: 0x13dc00d8>
<environment: 0x1a7aab10>
One way to modify lapply
or map
to work the way you think is to specify the environment for the assign
function:
lapply(1:6,function(i){
names<-str_c('var_lapply_',i)
assign(names,runif(30,20,100), envir = .GlobalEnv)
})
Note: If you are needing to use assign
you are probably writing code that would look better if you used a named list.
It is worth reading the chapter on Advanced R environments: https://adv-r.hadley.nz/environments.html