4

Hi I am trying to apply a list of functions to a single argument in R. For example,

flist <- list(F,G,H) #F,G,H are function objects

and say I want as a result a list or vector (F(x),G(x),H(x)) where x is a scalar number. Do you know how i can achieve that?

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
NickD1
  • 393
  • 1
  • 4
  • 14

2 Answers2

6

The most efficient way (it seems) to achieve this would be using a single lapply (instead of 3 different functions), such as

flist <- list(mean, unique, max) # Example functions list
MyScalar <- 1 # Some scalar
lapply(flist, function(f) f(MyScalar))
# [[1]]
# [1] 1
# 
# [[2]]
# [1] 1
# 
# [[3]]
# [1] 1

Though, if all the functions give the same size/class result, you could improve it even more using vapply

vapply(flist, function(x) x(MyScalar), FUN.VALUE = double(1))
## [1] 1 1 1
David Arenburg
  • 91,361
  • 17
  • 137
  • 196
3
f <- function(x) x^1
g <- function(x) x^2
h <- function(x) x^3
l <- list(f, g, h)

sapply(l, do.call, list(2))
## [1] 2 4 8

do.call allows for function delegation with variable-length argument lists. For example, c(1, 2, 3) can be called like so: do.call(c, list(1, 2, 3)). (s|l)apply just iterates through a list and applies the specified function to each item. So the first iteration through l will be: do.call(l[[1]], list(2)), which is equivalent to l[[1]](2), which is equivalent to f(2).

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
mmuurr
  • 1,310
  • 1
  • 11
  • 21
  • You should explain what the code does and what are the roles of the functions. – A.L Dec 14 '14 at 01:33
  • Well, the first 4 lines are simply setting up the example. – mmuurr Dec 14 '14 at 01:51
  • Let's imagine I came here from a search engine, I won't learn much by reading a block of code without any explanation. – A.L Dec 14 '14 at 01:53
  • Understood, but `R` has a (very) rich set of man pages for every function, conveniently named for nearly every function. For example, `?sapply` and `?do.call`. Any explanation I can give will do those man pages an injustice :-) – mmuurr Dec 14 '14 at 01:55
  • Thanks, that's a recommended practice here: *Brevity is acceptable, but fuller explanations are better*, see the documentation: http://stackoverflow.com/help/how-to-answer – A.L Dec 14 '14 at 01:58
  • Why would you use three functions such `sapply`, `do.call` and `list` instead of just a single `lapply`? – David Arenburg Dec 14 '14 at 12:51
  • (1) To introduce the OP to the concept of expression evaluation, which is a powerful tool. (2) The two solutions are roughly equivalent in speed, if taking the time to pre-store the argument list (i.e. removing the `list` call) and `sapply`'s simplification step. See [this gist](https://gist.github.com/mmuurr/71365206f19d0d3fe6c1) for a rough speed comparison. Efficiency wasn't a listed concern in the OP, and when that's the case, I tend to opt for solutions with increased flexibility. Great thing about `R` is that there's no shortage of solutions! (So I up-voted your answer, too :-) Cheers! – mmuurr Dec 14 '14 at 19:00
  • @DavidArenburg I find the do.call version more elegant, because there's no need to create anonymous functions. Same difference as `lapply(l, function(x) x[['id']])` vs `lapply(l, "[[", 'id')`. do.call is the natural function to apply here. – baptiste Dec 15 '14 at 12:35
  • @baptiste, why the lack of `function(x)` justifies so many additional functions? In the example you gave, there were no additional functions involved so I can agree with you on that, but this situation is completely different. In order to avoid `function(x)` you are adding additional 3 functions. That doesn't make any sense to me. – David Arenburg Dec 15 '14 at 12:56
  • @DavidArenburg I count only 1 _additional_ "function", and list() is a pretty lightweight player. Anyway, this is just a matter of personal preference. – baptiste Dec 15 '14 at 13:23