purrr - how to apply recursively a function n_times over one value

Viewed 737

I want to apply a function f() to one value n times.

For example, if I wanted to apply this function 5 times, I'd do something like:

f(f(f(f(f(1)))))

Is there any purrr solution for that?

For example, some function y such that:

y( 1, f, 5)
3 Answers

Here's one way using purrr::reduce. It's a bit of cheating (maybe not?) but seems to work. In the below demo I am recursively adding 3 to my initial value 5 times -

library(purrr)

x <- 1
n <- 5

rep(x, n+1) %>% reduce(function(x, y) x + 3)
# [1] 16

Here's the documentation for reduce -

.x A list or atomic vector.

.f For reduce(), a 2-argument function. The function will be passed the accumulated value as the first argument and the "next" value as the second argument.

By design reduce requires an x and y argument. While you must pass both to your function, you can choose not to use y like I have done. This means your function uses only the accumulated value recursively.

The intermediate steps can be seen using purrr::accumulate -

rep(x, n+1) %>% accumulate(function(x, y) x + 3)
# [1]  1  4  7 10 13 16

Notice that the function wasn't applied to the first instance and that's why you need n+1 in rep to get correct result.

EDIT 1: Here's a simplified version of above logic -

reduce(1:n, function(x, y) x + 3, .init = x)
# [1] 16

accumulate(1:n, function(x, y) x + 3, .init = x)
# [1]  1  4  7 10 13 16

EDIT 2: Here's a similar but simpler base R solution -

Reduce(function(x, y) x + 3, 1:n, init = x)
# [1] 16

Could use purrr::map and put that in a loop in y?

f <- function(n) n^2 # or any other function of n

y <- function(n, fun, k = 1) {

  x <- n
  for (i in 1:k) {
    x <- unlist(purrr::map(x, fun))
  }

  return(x)

}

# then to do f five times would be:
y(1, f, 5)

To make more robust you'd probably put some error handling in for the arguments.

This is the solution I have found. It looks a little verbose, but it works.

  reduce(
       rerun(5, f), 
  compose)(1)
Related