I cross posted this on Stack Overflow: http://stackoverflow.com/questions/27694466/chaining-multiple-replacement-functions-in-r I am using R to work with a large JS object (using the library rjsonio). As such, I have a lot of nested lists, which are getting somewhat cumbersome to work with. I have a simplified example below. I am trying to work with this object by creating some form of ?getter? and ?setter? functions. After looking around, I have found a pretty nice ?getter? function that recurses through the object and returns the value for the first matching label. This is especially great because it lends itself to chaining functions together. However, I can not figure out a way to get the same effect for a ?setter? function. Any thoughts on how to create a ?setter? function that can be chained together in a similar fashion? #example, simplified, object app = list( 1, 2, d=list(a=123, b=456, list( FirstKey=list(attr1='good stuff', attr2=12345), SecondKey=list(attr1='also good stuff', attr2=4321) ) ) ) #Return a function that returns the value #associated with first label that matches 'name' getByName <- function(name){ rmatch <- function(x) { pos <- match(name, names(x)) if (!is.na(pos)) return(x[[pos]]) for (el in x) { if (class(el) == "list") { out <- Recall(el) if (!is.null(out)) return(out) } } } rmatch } getFirstKey <- getByName("FirstKey") getAttr1 <- getByName("attr1") getAttr2 <- getByName("attr2") #I like that I can chain these functions together getAttr1(getFirstKey(app)) getAttr2(getFirstKey(app)) # I would like to be able to do something like this # But this won't work ### getAttr1(getFirstKey(app)) <- 9876 # This does work,,, but I loose the ability to chain functions together # Closure around a replacement function setterKeyAttr <- function(keyName, attr){ function(x, value){ x$d[[3]][[keyName]][[attr]] <- value x } } `setFirstKeyAttr2<-` <- setterKeyAttr("FirstKey", "attr2") setFirstKeyAttr2(app) <- 22222 #check the answer is correct getAttr2(getFirstKey(app)) references: http://stackoverflow.com/questions/23124096/r-decorator-to-change-both-input-and-output http://r.789695.n4.nabble.com/How-to-get-a-specific-named-element-in-a-nested-list-td3037430.html http://adv-r.had.co.nz/Functions.html [[alternative HTML version deleted]]
On 29/12/2014 4:41 PM, Daniel Gabrieli wrote:> I cross posted this on Stack Overflow: > http://stackoverflow.com/questions/27694466/chaining-multiple-replacement-functions-in-r > > > I am using R to work with a large JS object (using the library rjsonio). As > such, I have a lot of nested lists, which are getting somewhat cumbersome > to work with. I have a simplified example below. I am trying to work with > this object by creating some form of ?getter? and ?setter? functions. After > looking around, I have found a pretty nice ?getter? function that recurses > through the object and returns the value for the first matching label. This > is especially great because it lends itself to chaining functions together. > However, I can not figure out a way to get the same effect for a ?setter? > function. Any thoughts on how to create a ?setter? function that can be > chained together in a similar fashion?I haven't worked through the details here so this might not work, but the assignment function could add extra information saying which part of the object was modified. In the example below, "Firstkey" is app[[c(3,3,1)]], so a function that modified it could attach c(3,3,1) as an attribute, and later functions that wanted to do more things to it could start looking there. I guess the tricky part would be getting rid of that attribute if you didn't want to pass it along the chain, e.g. the final call shouldn't return it. Duncan Murdoch> > #example, simplified, object > app = list( > 1, > 2, > d=list(a=123, > b=456, > list( > FirstKey=list(attr1='good stuff', attr2=12345), > SecondKey=list(attr1='also good stuff', attr2=4321) > ) > ) > ) > > > #Return a function that returns the value > #associated with first label that matches 'name' > getByName <- function(name){ > rmatch <- function(x) { > pos <- match(name, names(x)) > if (!is.na(pos)) > return(x[[pos]]) > for (el in x) { > if (class(el) == "list") { > out <- Recall(el) > if (!is.null(out)) return(out) > } > } > } > rmatch > } > > getFirstKey <- getByName("FirstKey") > getAttr1 <- getByName("attr1") > getAttr2 <- getByName("attr2") > > #I like that I can chain these functions together > getAttr1(getFirstKey(app)) > getAttr2(getFirstKey(app)) > > # I would like to be able to do something like this > # But this won't work > ### getAttr1(getFirstKey(app)) <- 9876 > > # This does work,,, but I loose the ability to chain functions together > # Closure around a replacement function > setterKeyAttr <- function(keyName, attr){ > function(x, value){ > x$d[[3]][[keyName]][[attr]] <- value > x > } > } > > `setFirstKeyAttr2<-` <- setterKeyAttr("FirstKey", "attr2") > setFirstKeyAttr2(app) <- 22222 > #check the answer is correct > getAttr2(getFirstKey(app)) > > > > references: > > http://stackoverflow.com/questions/23124096/r-decorator-to-change-both-input-and-output > > http://r.789695.n4.nabble.com/How-to-get-a-specific-named-element-in-a-nested-list-td3037430.html > > http://adv-r.had.co.nz/Functions.html > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >
That is really helpful. I am trying to get the rmatch function to return the position of the 'name' instead of the value. So rmatch(app, "FirsKey") would return c(3,3,1). Then app[[c(3,3,1)]] <- 'new value' would be perfect. On Tue, Dec 30, 2014 at 6:43 AM, Duncan Murdoch <murdoch.duncan at gmail.com> wrote:> On 29/12/2014 4:41 PM, Daniel Gabrieli wrote: > > I cross posted this on Stack Overflow: > > > http://stackoverflow.com/questions/27694466/chaining-multiple-replacement-functions-in-r > > > > > > I am using R to work with a large JS object (using the library rjsonio). > As > > such, I have a lot of nested lists, which are getting somewhat cumbersome > > to work with. I have a simplified example below. I am trying to work with > > this object by creating some form of ?getter? and ?setter? functions. > After > > looking around, I have found a pretty nice ?getter? function that > recurses > > through the object and returns the value for the first matching label. > This > > is especially great because it lends itself to chaining functions > together. > > However, I can not figure out a way to get the same effect for a ?setter? > > function. Any thoughts on how to create a ?setter? function that can be > > chained together in a similar fashion? > > I haven't worked through the details here so this might not work, but > the assignment function could add extra information saying which part of > the object was modified. In the example below, "Firstkey" is > app[[c(3,3,1)]], so a function that modified it could attach c(3,3,1) as > an attribute, and later functions that wanted to do more things to it > could start looking there. > > I guess the tricky part would be getting rid of that attribute if you > didn't want to pass it along the chain, e.g. the final call shouldn't > return it. > > Duncan Murdoch > > > > > #example, simplified, object > > app = list( > > 1, > > 2, > > d=list(a=123, > > b=456, > > list( > > FirstKey=list(attr1='good stuff', attr2=12345), > > SecondKey=list(attr1='also good stuff', attr2=4321) > > ) > > ) > > ) > > > > > > #Return a function that returns the value > > #associated with first label that matches 'name' > > getByName <- function(name){ > > rmatch <- function(x) { > > pos <- match(name, names(x)) > > if (!is.na(pos)) > > return(x[[pos]]) > > for (el in x) { > > if (class(el) == "list") { > > out <- Recall(el) > > if (!is.null(out)) return(out) > > } > > } > > } > > rmatch > > } > > > > getFirstKey <- getByName("FirstKey") > > getAttr1 <- getByName("attr1") > > getAttr2 <- getByName("attr2") > > > > #I like that I can chain these functions together > > getAttr1(getFirstKey(app)) > > getAttr2(getFirstKey(app)) > > > > # I would like to be able to do something like this > > # But this won't work > > ### getAttr1(getFirstKey(app)) <- 9876 > > > > # This does work,,, but I loose the ability to chain functions together > > # Closure around a replacement function > > setterKeyAttr <- function(keyName, attr){ > > function(x, value){ > > x$d[[3]][[keyName]][[attr]] <- value > > x > > } > > } > > > > `setFirstKeyAttr2<-` <- setterKeyAttr("FirstKey", "attr2") > > setFirstKeyAttr2(app) <- 22222 > > #check the answer is correct > > getAttr2(getFirstKey(app)) > > > > > > > > references: > > > > > http://stackoverflow.com/questions/23124096/r-decorator-to-change-both-input-and-output > > > > > http://r.789695.n4.nabble.com/How-to-get-a-specific-named-element-in-a-nested-list-td3037430.html > > > > http://adv-r.had.co.nz/Functions.html > > > > [[alternative HTML version deleted]] > > > > ______________________________________________ > > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > > https://stat.ethz.ch/mailman/listinfo/r-help > > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > > and provide commented, minimal, self-contained, reproducible code. > > > >[[alternative HTML version deleted]]