how to access global/outer scope variable from R apply function?

19,333

Solution 1

Using the <<- operator you can write to variables in outer scopes:

x = data.frame(age=c(11,12,13), weight=c(100,105,110))
x

testme <- function(df) {
    i <- 0
    apply(df, 1, function(x) {
        age <- x[1]
        weight <- x[2]
        cat(sprintf("age=%d, weight=%d\n", age, weight))
        i <<- i+1   #this could not access the i variable in outer scope
        z <<- z+1   #this could not access the global variable
    })
    cat(sprintf("i=%d\n", i))
    i
}

z <- 0
y <- testme(x)
cat(sprintf("y=%d, z=%d\n", y, z))

The result here:

age=11, weight=100
age=12, weight=105
age=13, weight=110
i=3
y=3, z=3

Note that the usage of <<- is dangerous, as you break up scoping. Do this only if really necessary and if you do, document that behavior clearly (at least in bigger scripts)

Solution 2

try the following inside your apply. Experiment with the value of n. I believe that for i it should be one less than for z.

         assign("i", i+1, envir=parent.frame(n=2))
         assign("z", z+1, envir=parent.frame(n=3))



testme <- function(df) {
    i <- 0
    apply(df, 1, function(x) {
        age <- x[1]
        weight <- x[2]
        cat(sprintf("age=%d, weight=%d\n", age, weight))

        ## ADDED THESE LINES
         assign("i", i+1, envir=parent.frame(2))
         assign("z", z+1, envir=parent.frame(3))

    })
    cat(sprintf("i=%d\n", i))
    i
}

OUTPUT

> z <- 0
> y <- testme(x)
age=11, weight=100
age=12, weight=105
age=13, weight=110
i=3
> cat(sprintf("y=%d, z=%d\n", y, z))
y=3, z=3     
Share:
19,333
fatdragon
Author by

fatdragon

Updated on June 12, 2022

Comments

  • fatdragon
    fatdragon almost 2 years

    I can't seem to make apply function access/modify a variable that is declared outside... what gives?

        x = data.frame(age=c(11,12,13), weight=c(100,105,110))
        x
    
        testme <- function(df) {
            i <- 0
            apply(df, 1, function(x) {
                age <- x[1]
                weight <- x[2]
                cat(sprintf("age=%d, weight=%d\n", age, weight))
                i <- i+1   #this could not access the i variable in outer scope
                z <- z+1   #this could not access the global variable
            })
            cat(sprintf("i=%d\n", i))
            i
        }
    
        z <- 0
        y <- testme(x)
        cat(sprintf("y=%d, z=%d\n", y, z))
    

    Results:

        age=11, weight=100
        age=12, weight=105
        age=13, weight=110
        i=0
        y=0, z=0