Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: creating an environment in the globalenv() from inside a function

Tags:

r

Right now I have the lines:

envCache <- new.env( hash=TRUE, parent = .GlobalEnv )
print(parent.env(envCache))

R claims the environment is in the global environment, but when I try to find the environment later it's not there.

What I'm trying to do here is cache some dataframes in and environment under the global environment, so each time I call a function it does not have to hit the server to get the same data again. Ideally, I'll call the function once using a source command in the R console, it will grab the data necessary, save it to an environment in the global environment, and then when I call the same function from the R console it will see the environment and dataframe from which it will grab the data as opposed to re-querying the server.

like image 896
Nick Burroughs Avatar asked Jun 16 '11 17:06

Nick Burroughs


2 Answers

When R looks for a symbol, it looks in the current environment, then the environment's parent, and so on. It has not assigned envCache into the global environment. One way to implement what you would like to do is to create a 'closure' that remembers state, along the lines of

makeCache <- function() {
    cache <- new.env(parent=emptyenv())
    list(get = function(key) cache[[key]],
         set = function(key, value) cache[[key]] <- value,
         ## next two added in response to @sunpyg
         load = function(rdaFile) load(rdaFile, cache),
         ls = function() ls(cache))
}

invoking makeCache() returns a list of two functions, get and set.

a <- makeCache() 

Each function has an environment in which it was defined (the environment created when you invoked makeCache()). When you invoke a$set("a", 1) the rules of variable look-up mean that R looks for a variable cache, first inside the function aCache$set, and when it doesn't find it there in the environment in which set was defined.

> a$get("foo")
NULL
> a$set("foo", 1)
> a$get("foo")
[1] 1

Cool, eh? Note that parent=emptyenv()) means that a get() on a non-existent keys stops looking in cache, otherwise it would have continued to look in the parent environment of cache, and so on.

There's a bank account example in the Introduction to R document that is really fun. In response to @sunpyg's comment, I've added a load and ls function to add data from an Rda file and to list the content of the cache, e.g., a$load("foo.Rda").

like image 89
Martin Morgan Avatar answered Nov 15 '22 10:11

Martin Morgan


Here's what I came up with as an alternate solution. It may be doing the same thing as the other answer in the backround, but the code is more intuitive to me.

cacheTesting <- function()
{
    if (exists("cache"))
    { 
        print("IT WORKS!!!") 
        cacheData <- get("test", envir = cache)
        print(cacheData)
    }
    else
    {   
        assign("cache", new.env(hash = TRUE), envir = .GlobalEnv) 
        test <- 42
        assign("test", test, envir = cache) 
    }
}

The first run of the code creates the environment in the .GlobalEnv using an assign statement. The second run sees that environment, because it actually made it to .GlobalEnv, and pulls the data placed there from it before printing it.

like image 42
Nick Burroughs Avatar answered Nov 15 '22 12:11

Nick Burroughs