Search code examples
renvironment-variablesenvironmentassignment-operator

Assign values to part of an object in another environment in R


Suppose I have two similar big objects x, y (datatable) defined in an envirnomnet e. I would like to change a big part of x or y in a similar way using a function f without creating a copy of x or y within the executive environment of f. Example:

e <- new.env()
e$x <- c(1,2,3) # imagine this to be BIG (ie. dataframe with 200k vars each 500k rows)
e$y <- c(4,5,6) # same here
e$v <- 2        # minor variables 

f <- function(var_str, env, input){

    # do some computation on parts of var_str which is either "x" or "y"
    # and store these right back into e$x or e$y, respectively.
    # ie

    str <- paste0(var_str,"[2:3] <- (",var_str,"[2:3])^2 + rep(v,2) + ", deparse(input1),"^3/c(100,101)")
    eval(parse(text=str), envir= e)

    # this does work but I can image there is an easier/more elegant way 
    # of doing this.
}

I would like to define the function in the global environment and apply this function to e$x and e$y with different variables in input. Ie. execute

f("x", e, c(1,2))
f("y", e, c(3,4))

Does anybody have an elegant solution to this.


Solution

  • Out of curiosity I tried working with the simple example in the R6 tutorial and came up with this (copied as a console transcript). I honestly didn't know if it complies with the non-copy requirements of the request, but it does appear to modify an object in-place.

    # Assumes one has created an R6 constructor named `RC` ...
    # slightly extended from the example in section
    RC <- setRefClass("RC",
      fields = list(x = 'ANY'),
      methods = list(
        getx = function() x,
        setx = function(value) x <<- value,
        setsub = function(i,j,val) x[i,j] <<- val
      )
    )
    
    #--- execution --- 
    rc <- RC$new()
    rc$setx(matrix(1:20, 4,5))
    rc
    # --- result ---    
    Reference class object of class "RC"
    
    Field "x":
         [,1] [,2] [,3] [,4] [,5]
    [1,]    1    5    9   13   17
    [2,]    2    6   10   14   18
    [3,]    3    7   11   15   19
    [4,]    4    8   12   16   20
    

    Test the setsub class-specific function:

    rc$setsub(4,5,0)   #Test of setting a single element within an object to a new value
    rc
    #-------    
    Reference class object of class "RC"
    Field "x":
         [,1] [,2] [,3] [,4] [,5]
    [1,]    1    5    9   13   17
    [2,]    2    6   10   14   18
    [3,]    3    7   11   15   19
    [4,]    4    8   12   16    0
    
    rc$setsub(1:4,1:4,0)    #Test of setting a range of elements within an object to a new value
    rc
    # ---------
    Reference class object of class "RC"
    Field "x":
         [,1] [,2] [,3] [,4] [,5]
    [1,]    0    0    0    0   17
    [2,]    0    0    0    0   18
    [3,]    0    0    0    0   19
    [4,]    0    0    0    0    0
    

    So this (very lightly tested) implementation of the [<--function via setsub does succeed. A single effort to extend this to the example using a self reference did fail.