4

I was wondering if there's a simple way to combine the functions of rapply( , how = "replace") and mapply(), in order to use mapply() on nested lists recursively.

For instance, I have two nested lists:

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

Let's say I want to apply function(x, y) x + y to all the corresponding elements in A and B and preserve the nested structure. The desired result would be

result = list(list(c(2,4,6), c(4,6,8)), list(c(8,6,4), c(6,4,2)))

I think this should be a mapply() analog of rapply(x, f, how = "replace"), but couldn't figure out how to integrate them. Could anyone kindly give me some pointers on this?

Another quick question is, which is usually faster for intensive computation, nested lists or multidimensional arrays? Any comments are very much appreciated!

Henrik
  • 65,555
  • 14
  • 143
  • 159
shenglih
  • 879
  • 2
  • 8
  • 18

2 Answers2

4

Or you can write a recursive function combined with Map to achieve this, which works as long as A and B have the same structure:

s <- function(x, y) tryCatch(x + y, error = function(e) Map(s, x, y))
s(A, B)

[[1]]
[[1]][[1]]
[1] 2 4 6

[[1]][[2]]
[1] 4 6 8


[[2]]
[[2]][[1]]
[1] 8 6 4

[[2]][[2]]
[1] 6 4 2

Not sure if you can use rapply in this case, which loops through a single list recursively. But in order to loop through two lists recursively at the same time, you need a higher level of recursion? Am I wrong?

Psidom
  • 209,562
  • 33
  • 339
  • 356
  • Thanks so much Psidom! I realized this is so neat and more general than the above solution!! – shenglih Jun 19 '16 at 14:03
  • 1
    to avoid the overhead of `tryCatch` an alternative `s` might be: `function(x, y) if(is.atomic(x) && is.atomic(y)) x + y else Map(s, x, y)` – alexis_laz Jun 19 '16 at 15:44
1

You can use Map recursively (twice) to accomplish this:

Map(function(i, j) Map(function(x, y) x + y, i, j), A, B)

[[1]]
[[1]][[1]]
[1] 2 4 6

[[1]][[2]]
[1] 4 6 8


[[2]]
[[2]][[1]]
[1] 8 6 4

[[2]][[2]]
[1] 6 4 2

To use mapply, you would need simplify=FALSE, but that is the default for Map. The outer list elements are fed to the first Map and the inner list elements are fed to the second Map.

lmo
  • 37,904
  • 9
  • 56
  • 69
  • Thanks so much Imo! I was wondering would you mind also demonstrating how to use Reduce() recursively? Something like Reduce(function(x) Reduce('+', x), A) which is a buggy attempt to recursively sum up the vectors in A... – shenglih Jun 19 '16 at 13:56
  • I can give it a try @MeredithHu, but this should be asked as a separate question because as below, others may provide some neat solutions. – lmo Jun 19 '16 at 13:59