Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: How to create a vector of functions?

Tags:

r

I would like to create a vector of functions using a two agruments function 'func', for instance this one:

func = function(number, coefficient) {  
    return(coefficient*number)  
}

here is how I create the vector of functions:

vector_of_functions = NULL  
for (i in 1:4) {  
vector_of_functions = c(vector_of_functions,
    function(number) func(number=number, coefficient=i))  
}

My issue is that all functions that compose my vector are the same, even if they have been created using different i through the loop. It seams that they are evaluated using the last value of i (which is here a global variable).

Anybody has an idea?

Thanks

like image 637
RockScience Avatar asked Oct 21 '10 08:10

RockScience


2 Answers

You can "attach" the value of i to each function by redefining i in its own local environment (conveniently created by the function, local in R). The resulting function with data "attached" is called a 'closure'.

> vector_of_functions = NULL  
> for (i in 1:4) {  
+ vector_of_functions = c(vector_of_functions,
+     local({i <- i;function(number) func(number=number, coefficient=i)}))
+ }
> vector_of_functions[[1]](1)
[1] 1
> vector_of_functions[[2]](1)
[1] 2
> vector_of_functions[[3]](1)
[1] 3
> vector_of_functions[[4]](1)
[1] 4
like image 142
hatmatrix Avatar answered Sep 21 '22 01:09

hatmatrix


This can be solved using an eval-parse construct, although I strongly advice you not to use this construct. It often causes more problems than anything else. But I couldn't get a decent do.call way of doing it.

vector_of_functions = NULL
for (i in 1:4) {
vector_of_functions = c(vector_of_functions,
  eval(parse(text=paste("function(number) func(number=number, coefficient=",i,")"))))
}

Reason is as Aaron explained: everything within the function definition is taken as is until the function evaluation.

Small remark: this is especially a list of functions, and not a vector. It's impossible to have a vector of type "function". It's also absolutely useless, as you have to select the function using the index [[]] before you can use it. Then I'd just add the argument instead of defining a function for every possible value of one of the arguments.

So what you want to achieve is unclear, but if you want to apply func with different coefficients, I wonder why you don't simply do:

> x <- c(10,20,30)
> sapply(1:4,function(y)func(number=x,coefficient=y))
     [,1] [,2] [,3] [,4]
[1,]   10   20   30   40
[2,]   20   40   60   80
[3,]   30   60   90  120

A variation on the theme by Marek (avoiding the parsing):

vector_of_functions = NULL
for (i in 1:4) {
vector_of_functions = c(vector_of_functions,
  eval(substitute(function(number) func(number=number, coefficient=i),list(i=i))))
}

The 1L etc. you get, just indicate they're exact integers (that take less memory space).

like image 30
Joris Meys Avatar answered Sep 19 '22 01:09

Joris Meys