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.gabri...@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.dun...@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@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]] ______________________________________________ R-help@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.