Assign multiple objects to .GlobalEnv from within a function
Update of 2018-10-10:
The most succinct way to carry out this specific task is to use list2env()
like so:
## Create an example list of five data.frames
df <- data.frame(x = rnorm(25),
g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)
## Assign them to the global environment
list2env(LIST, envir = .GlobalEnv)
## Check that it worked
ls()
## [1] "A" "B" "C" "D" "df" "E" "LIST"
Original answer, demonstrating use of assign()
You're right that assign()
is the right tool for the job. Its envir
argument gives you precise control over where assignment takes place -- control that is not available with either <-
or <<-
.
So, for example, to assign the value of X
to an object named NAME
in the the global environment, you would do:
assign("NAME", X, envir = .GlobalEnv)
In your case:
df <- data.frame(x = rnorm(25),
g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)
NAMES <- c("V", "W", "X", "Y", "Z")
lapply(seq_along(LIST),
function(x) {
assign(NAMES[x], LIST[[x]], envir=.GlobalEnv)
}
)
ls()
[1] "df" "LIST" "NAMES" "V" "W" "X" "Y" "Z"
Assign to .GlobalEnv with assign
That works: Change ListContainer to:
ListContainer=c("theList1","theList2")
Was some issue with deparse(substitute(..))
part.
Or maybe that could work too with some adjustments:
ListContainer=c(quote(theList1),quote(theList2))
and then
eval(ListContainer[i])
in the loop.
Saving R objects to global environment from inside a nested function called by a parent function using mcmapply
(Sorry, I'll write this as an 'Answer' because the comment box is too brief)
The best solution to your problem would be to make sure you return the objects you produce rather than trying to assign them from inside a function to an external environment [edit 2020-01-26] which never works in parallel processing because parallel workers do not have access to the environments of the main R process.
A very good rule of thumb in R that will help you achieve this: Never use assign()
or <<-
in code - neither for sequential nor for parallel processing. At best, you can get such code to work in sequential mode but, in general, you will end up with hard to maintain and error-prone code.
By focusing on returning values (y <- mclapply(...)
in your example), you'll get it right. It also fits in much better with the overall functional design of R and parallelizes more naturally.
I've got a blog post 'Parallelize a For-Loop by Rewriting it as an Lapply Call' from 2019-01-11 that might help you transition to this functional style.
How to assign function defaults to R .GlobalEnv
Try this:
ff <- f
body(ff) <- quote(environment())
Now this will put them in the global environment:
list2env(as.list(ff()), .GlobalEnv)
or this will attach them to the search path:
attach(ff())
Note 1
a
and b
are normal variables but c
is represented by a missing value so although it will be in the global environment or search path you can't print it; however, you can query whether or not it is such a variable like this:
inherits(try(c, silent = TRUE), "try-error")
## [1] TRUE
That expression will be FALSE for variables having a value.
Note 2
To only copy only the arguments having defaults to the global environment:
ff <- f
body(ff) <- quote({
L <- as.list(environment())
is_missing <- sapply(names(L), function(x) {
x <- as.list(ff)[[x]]
missing(x)
})
L[! is_missing]
})
list2env(ff(), .GlobalEnv)
or to attach them replace the last line with:
attach(ff())
How to use the R environment and the globalenv() function
Your card deck is stored in a vector deck
in your Global Environment.
deal <- function(){
card <- deck[1,]
assign("deck", deck[-1,], envir = globalenv())
card
}
Each function call creates it's own environment, an object assigned inside a function "lives" just inside of it. That's why you don't "see" a vector named card
in your Global Environment (unless you created one before, but this vector is uneffected by deal
functions card <- deck[1,]
statement).
So assign("deck", deck[-1])
(without the envir
argument) would be the same as
deal <- function(){
card <- deck[1,]
deck <- deck[-1,]
card
}
but this won't change your deck
outside the function. The vector deck
inside the function just exists inside the function. To change the deck
outside the function, you have to tell R
where to change it. So that's why assign("deck", deck[-1,], envir = globalenv())
is used.
So let's start over with your function deal
:
card <- deck[1,]
assigns the first element of deck
to card
. But wait! deck
doesn't exists inside the function? So how is this possible? If the object isn't found inside the function, R
looks one level up, in your case most likely the Global Environment. So there R finds an object/vector named deck
and does the assignment. Now we have an object/vector named card
that exists inside the function.
For further understanding, take a look at Chapter 6: Functions in Advanced R.
Overwriting an object in the global environment after using deparse(substitute()) in a function call
You can fix this by using deparse(substitute(data))
before you do anything to data
:
# Let's change your function just a bit
change.name <- function(data){
# call deparse(substutite()) *before* you do anything to data
object_name <- deparse(substitute(data))
for (i in 1:length(data)){
names(data[[i]]) <- c("a", "b", "c", "d", "e")
}
assign(object_name, value = data, envir = globalenv())
}
# Create sample data
my_object1 <- lapply(1:12, function(x) {
data.frame(u = 1, v = 2, x = 3, y = 4, z = 5)
})
names(my_object1) <- month.name
change.name(my_object1)
ls()
#> [1] "change.name" "my_object1"
head(my_object1, 2)
#> $January
#> a b c d e
#> 1 1 2 3 4 5
#>
#> $February
#> a b c d e
#> 1 1 2 3 4 5
Created on 2018-12-20 by the reprex package (v0.2.1)
Related Topics
Idiomatic R Code For Partitioning a Vector by an Index and Performing an Operation on That Partition
Horizontal/Vertical Line in Plotly
Find Which Season a Particular Date Belongs To
How to Display Only Integer Values on an Axis Using Ggplot2
How to Position Two Legends Independently in Ggplot
Removing Empty Rows of a Data File in R
Combining Two Data Frames of Different Lengths
How to Load Packages in R Automatically
Finding All Positions For Multiple Elements in a Vector
Invalid Multibyte String in Read.Csv
Finding Rows Containing a Value (Or Values) in Any Column
Ggplot2 Keep Unused Levels Barplot
Aggregate Multiple Columns At Once
How to Subtract/Add Days From/To a Date
Use Variable Names in Functions of Dplyr
Select Multiple Columns in Data.Table by Their Numeric Indices
Add a Variable to a Data Frame Containing Max Value of Each Row