1

Disclaimer: this is not a duplicate of this question: How to combine rapply() and mapply(), or how to use mapply/Map recursively? On top of that question, I am asking how to incorporate extra arguments of functions into the recursion.

So I have lists:

A = list(list(list(c(1,2,3), c(2,3,4)),list(c(1,2,3),c(2,3,4))), list(c(4,3,2), c(3,2,1)))
B = list(list(list(c(1,2,3), c(2,3,4)),list(c(1,2,3),c(2,3,4))), list(c(4,3,2), c(3,2,1)))

And I need to apply different functions to it recursively that preserves the list structure. Presumably, a recursive function that does this goes like this, when the function is mean():

recursive = function(x, y){
  if(is.null(y)){
    if(is.atomic(x)){
      x*x
    } else{
      Map(recursive, x)
    }
  } else{
    if(is.atomic(y) && is.atomic(x)){
      x*y
    } else{
      Map(recursive, x, y)
    }
  }
}

So the desired result would be:

recursive(A,B)

I was wondering how could I generalize this recursion to any functions beyond just the hard-coded function(x,y) x*y here so that I could change functions conveniently? In that case, it would start with:

recursive = function(somefunction, x, y){
....
}

where

somefunction = function(x,y) x*y #or any other function taking x and y as inputs

Could anyone kindly show me a way out? Thank you so much.

Community
  • 1
  • 1
shenglih
  • 879
  • 2
  • 8
  • 18
  • Hi @akrun this is not a duplicate question of what I asked before... – shenglih Jun 23 '16 at 16:04
  • It's not clear to me what the desired result is here. What exactly are you trying to do with this list? – MrFlick Jun 23 '16 at 16:14
  • Hi @MrFlick, thanks for commenting! I am trying to apply many different functions to nested lists and would like a general recursive function into which I can conveniently plug various functions... – shenglih Jun 23 '16 at 16:16
  • 1
    That doesn't make things any more clear. That sounds like what `rapply()` is for. Why doesn't that work for you? A [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output would be helpful – MrFlick Jun 23 '16 at 16:18
  • 1
    Quickly modifying your linked Q, it seems that you could use something like `ff = function(x, y, fun) if(is.atomic(x) && is.atomic(y)) match.fun(fun)(x, y) else Map(ff, x, y, fun)`. And -with `A` and `B` from the linked Q- `ff(A, B, "+")`, `ff(A, B, "-")` etc – alexis_laz Jun 23 '16 at 16:26
  • @MrFlick, yes rapply() would be one simplification where the recursive functions traverse over only one list... but I need multiple lists like what Map() does... – shenglih Jun 23 '16 at 18:04
  • @MrFlick, thanks for your comments! I believe I've changed the question to be much clearer now... – shenglih Jun 23 '16 at 18:16
  • @alexis_laz, thanks so much for your code! It works great! I was just wondering why doesn't it work for other functions? Does it work only for `"+"` and `"-"`? – shenglih Jun 23 '16 at 18:23
  • @MeredithHu : I overlooked `Map`'s arguments and `fun` was passed as `...` and by accident functions passed as "character" work -- MrFlick got it right – alexis_laz Jun 23 '16 at 21:12

1 Answers1

3

You can use

recursive  <- function(fun, x, y) {
    if(is.atomic(x) && is.atomic(y)) {
        match.fun(fun)(x, y) 
    } else  {
        Map(recursive, x, y, MoreArgs=list(fun=fun))
    }
}

The reason is that Map calls mapply and mapply has a MoreArgs= parameter where you can specify other parameters you want to pass to the calling function that you do not want to iterate over.

MrFlick
  • 195,160
  • 17
  • 277
  • 295