Search code examples
rlistpurrraccumulatecombn

purrr - how to apply recursively a function with changing arguments


Ideally I would like to make use of purrr's accumulate function or similar.

Let's say I want to make use of utils::combn function iteratively, and get all the intermediate results (ideally put inside a list of lists).

In example below, initially, parameter x = 4, thus m will be also 4 (but (x, m) could be (5, 5), (6, 6), ...). Then, after first loop, x will be previous result, whilst m goes down by one, iteratively until m = 2.

n1 <- combn(x = 4, m = 4, simplify = FALSE) 
n2 <- map(n1, ~ combn(.x, 3, simplify = FALSE)) 
n3 <- map(n2, ~ map(., ~ combn(.x, 2, simplify = FALSE)))

> n1
[[1]]
[1] 1 2 3 4


> n2
[[1]]
[[1]][[1]]
[1] 1 2 3

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

[[1]][[3]]
[1] 1 3 4

[[1]][[4]]
[1] 2 3 4

> n3
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] 1 2

[[1]][[1]][[2]]
[1] 1 3

[[1]][[1]][[3]]
[1] 2 3


[[1]][[2]]
[[1]][[2]][[1]]
[1] 1 2

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

[[1]][[2]][[3]]
[1] 2 4


[[1]][[3]]
[[1]][[3]][[1]]
[1] 1 3

[[1]][[3]][[2]]
[1] 1 4

[[1]][[3]][[3]]
[1] 3 4


[[1]][[4]]
[[1]][[4]][[1]]
[1] 2 3

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

[[1]][[4]][[3]]
[1] 3 4

As you can imagine, I want to get all possible combinations, e.g.:

choose(4, 4) -> choose(result, 3) -> choose(result, 2).

How can I do this?


Solution

  • You can use accumulate + map_depth:

    combn_recur <- function(n) {
      accumulate(c(n, 0:(n-2)),
                 ~ map_depth(.x, .y, combn, m = n-.y, simplify = FALSE))[-1]
    }
    
    all.equal(combn_recur(4), c(n1, n2, n3))
    # TRUE
    
    combn_recur(3)
    # [[1]]
    # [1] 1 2 3
    # 
    # [[2]]
    # [[2]][[1]]
    # [1] 1 2
    # 
    # [[2]][[2]]
    # [1] 1 3
    # 
    # [[2]][[3]]
    # [1] 2 3
    
    combn_recur(2)
    # [[1]]
    # [1] 1 2
    
    combn_recur(1)
    # Error in .f(.x[[i]], ...) : n < m