Jouni Helske
Jouni Helske

Reputation: 6477

How to write an R function which assigns to the object of the calling environment?

I have a objects of certain class which contain several matrices, and I would like to build a function which access and possibly modifies subset of such matrix. For example:

foo<-list(x=diag(1:4),y=matrix(1:8,2,4))
class(foo)<-"bar"
attr(foo,"m")<-4
attr(foo,"p")<-2
rownames(foo$x)<-colnames(foo$x)<-colnames(foo$y)<-c("a.1","b.1","b.2","c.1")
attr(foo,"types")<-c("a","b","b","c")

Now I could access and modify certain elements like this:

foo$x[attr(foo,"types")%in%c("c","b"),attr(foo,"types")%in%c("c","b")]    
foo$x[attr(foo,"types")%in%c("c","b"),attr(foo,"types")%in%c("c","b")]<-matrix(5,3,3)

But instead of the above, I would like to construct a following type of function:

modify<-function(object,element,types){
  # check that the object is proper class, 
  # and the element and the types are found in the object

  # this returns to the local copy of the corresponding subset:
   object[[element]][attr(object,"types")%in%types,attr(object,"types")%in%types]     
}

For accessing the above function is ok, but what if I want to modify the original object? Obviously this doesn't work:

modify(foo,"x",c("c","b"))<-matrix(5,3,3)
Error in modify(foo, "x", c("c", "b")) <- matrix(5, 3, 3) : 
  could not find function "modify<-

Is it possible to get that work somehow? If not, one option I could think of is adding argument replace.with to function modify and then making the assignment first to the local copy and then copying the change to the object in the calling environment using assign function. For this I would need to find the original object in the calling environment, but I'm not sure how to do that.

Upvotes: 0

Views: 275

Answers (2)

Jouni Helske
Jouni Helske

Reputation: 6477

Ok, I found a solution myself with a help of old post from R-help by Brian Ripley:

foo<-list(x=diag(1:4),y=matrix(1:8,2,4))
class(foo)<-"bar"
attr(foo,"m")<-4
attr(foo,"p")<-2
rownames(foo$x)<-colnames(foo$x)<-colnames(foo$y)<-c("a.1","b.1","b.2","c.1")
attr(foo,"types")<-c("a","b","b","c")

`modify<-` <- function(x, element, subset,value) UseMethod("modify<-")
`modify<-.bar` <- function(x, element, subset,value) { 

  x[[element]][,attr(foo,"types")%in%subset] <- value
  x }

modify(foo,"x",c("c","b"))<-matrix(5,3,3)
foo$x
    a.1 b.1 b.2 c.1
a.1   1   0   0   0
b.1   0   5   5   5
b.2   0   5   5   5
c.1   0   5   5   5

Upvotes: 0

Ricardo Saporta
Ricardo Saporta

Reputation: 55350

With the caveat that this is generally frowned upon, you can use the following:

From the target environment, set a variable to the environment and then pass that as an argument to your function which you can use in assign, get etc

en <- environment()
myfunc <- function(..., en=en) {
  . etc .
  assign("varname", envir=en)
}

Note that if you are simply changing attributes, the setattr function of the data.table package already implements this quote nicely:

 setattr(x,name,value)

Upvotes: 1

Related Questions