For example, I have a vector of functions: fun_vec <- c(step1,step2,step3)
.
Now I want to compose them like this: step1(step2(step3(x)))
. How do I do this using fun_vec
? (Suppose that fun_vec
isn't fixed and can have more or less functions.)
Asked
Active
Viewed 350 times
5

Jaap
- 81,064
- 34
- 182
- 193

Catiger3331
- 611
- 1
- 6
- 18
4 Answers
5
Similar to Frank's use of freduce
, you can use Reduce
:
step1 <- function(a) a^2
step2 <- function(a) sum(a)
step3 <- function(a) sqrt(a)
steps <- list(step1, step2, step3)
Reduce(function(a,f) f(a), steps, 1:3)
# [1] 3.741657
step3(step2(step1(1:3)))
# [1] 3.741657
You can see it "in action" with:
Reduce(function(a,f) f(a), steps, 1:3, accumulate=TRUE)
# [[1]]
# [1] 1 2 3
# [[2]]
# [1] 1 4 9
# [[3]]
# [1] 14
# [[4]]
# [1] 3.741657

r2evans
- 141,215
- 6
- 77
- 149
4
You can use freduce from the magrittr package:
fun_vec = c(function(x) x^2, function(x) sum(x), function(x) sqrt(x))
library(magrittr)
freduce(1:10, fun_vec)
Alternately, define a function sequence with pipes like...
library(magrittr)
f = . %>% raise_to_power(2) %>% sum %>% sqrt
f(1:10)
A similar example: Is there a way to `pipe through a list'?

Frank
- 66,179
- 8
- 96
- 180
3
Here's a base R recursive approach:
compose <- function(funs) {
n <- length(funs)
fcomp <- function(x) funs[[n - 1]](funs[[n]](x))
ifelse(n > 2, compose(c(funs[1:(n - 2)], fcomp)), fcomp)
}
x <- c(sqrt, log, exp)
compose(x)(2)
# [1] 1.414214
sqrt(log(exp(2)))
# [1] 1.414214
If the number of functions in funs
is greater than two, we shorten the list by one by replacing the last two functions by their composition. Otherwise, we return the composition of the last remaining two. It's assumed that initially there are at least two functions in funs
.

Julius Vainora
- 47,421
- 9
- 90
- 102
-
Is there a reason for using `ifelse` vice just `if` here? – r2evans Oct 23 '18 at 19:02
-
1Only compactness. – Julius Vainora Oct 23 '18 at 19:04
-
3Then using `if` with the backticks, as a regular function, will be more compact and more correct – moodymudskipper Oct 23 '18 at 19:52
2
Take a look at purrr::compose
. If your functions are stored inside a list, use purrr::invoke
to pass that list to compose
:
fun_vec <- c( exp, log10, sqrt )
f <- purrr::invoke( purrr::compose, fun_vec )
f(4) # 1.35125
exp( log10( sqrt(4) ) ) # 1.35125

Artem Sokolov
- 13,196
- 4
- 43
- 74
-
1I guess they'll make `compose(!!!fun_vec)` work at some point, but not yet – moodymudskipper Oct 24 '18 at 19:35
-
1@Moody_Mudskipper [Funny you should mention that](https://github.com/tidyverse/purrr/issues/564) :) – Artem Sokolov Oct 24 '18 at 19:41