Assign Multiple Objects to .Globalenv from Within a Function

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



Leave a reply



Submit