[R] Chaining multiple replacement functions in R
Daniel Gabrieli
daniel.gabrieli at gmail.com
Tue Dec 30 22:51:10 CET 2014
This is what I came up with (to make the recursive function return the
position of the 'name' and still be able to chain the calls together). I
am not sure if this is a great way to do it... but it seems to be
working...
rmatch.pos <- function(object, name, seq=NA, level=NULL){
##return the vector of integers corresponding to the first match
##of 'name' to a label in object or NULL if no match is found
###object: a list, likely deeply nested
##name: the name of the label to look for
##seq: starting point to search for 'name' in 'object' i.e. c(2,3,3)
##level: don't touch this; it keeps track of how deep the recursive
execution is
##can be chained together to reduce ambiguity or result:
##obj <- list(a=1, b=list(c=2, d=list(e=1, attr1="really?",
f=list(attr1 = "found me!"))))
##obj[[rmatch.pos(obj, "attr1", rmatch.pos(obj, "f"))]]
if(is.null(seq)){
#short circuit if NULL gets passed
#when chaining, this forces the whole 'chain'
#to NULL when any 'link' is NULL
return(NULL)
}
if(is.null(level)){
level <- length(na.omit(seq))
}
if(any(is.na(seq))){
temp <- object
}else{
temp <- object[[seq]]
}
level <- level + 1
pos <- match(name, names(temp))
if(!is.na(pos)){
seq[level] <- pos
return(seq)
}
for(el in seq_along(temp)){
if(class(temp[[el]]) == "list"){
seq[level] <- el
out <- Recall(object, name, seq, level)
if(!is.null(out)){
return(out)
}
}
}
}
rmatch.pos(app, "ThirdKey")
rmatch.pos(app, "attr2")
#chaining example
rmatch.pos(app, "attr2", rmatch.pos(app, "FirstKey"))
rmatch.pos(app, "attr2", rmatch.pos(app, "SecondKey"))
rmatch.pos(app, "attr1", rmatch.pos(app, "ERROR"))
rmatch.pos(app, "ERROR", rmatch.pos(app, "attr1"))
On Tue, Dec 30, 2014 at 1:08 PM, Daniel Gabrieli <daniel.gabrieli at gmail.com>
wrote:
> 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]]
More information about the R-help
mailing list