Choubi Choubi - 3 months ago 9
R Question

Creating functions in a for loop with lists

I am scratching my head at the following problem:

I am creating two functions inside a for loop with parameters that depend on some dataframe. Each function is then put inside a list.

Printing the parameters inside the for loop shows that eachh function is well defined. Yet, when I use those outside of the loop, only the last parameters are used for both functions. The following example should make that clearer.

dt <- data.frame(color = c("red", "blue"),
a = c(3,9),
b = c(1.3, 1.8))
function_list <- list()
for (col in dt$color) {
a <- dt$a[dt$color == col]
b <- dt$b[dt$color == col]

foo <- function(x) {
a*x^b
}
print(paste(col, foo(1)))
function_list[[col]] <- foo
}



[1] "red 3"

[1] "blue 9"


function_list[["red"]](1)



[1] 9


function_list[["blue"]](1)



[1] 9


To note, this is inspired from the following question: R nested for loop to write multiple functions and plot them

The equivalent solution with
assign
and
get
works (my answer to the previous question).

Answer

The relevant values of a and b are those when you call the function and not when you define it. The way you create the list, they are taken from the global environment. The solution is to create closures. I'd use Map for this, but you can do the same with a for loop:

funs <- Map(function(a, b) function(x) a*x^b, a = dt$a, b = dt$b)

print(funs)
#[[1]]
#function (x) 
#a * x^b
#<environment: 0x000000000a9a4298>
#
#[[2]]
#function (x) 
#a * x^b
#<environment: 0x000000000a9a3728>

Notice the different environments.

environment(funs[[1]])$a
#[1] 3
environment(funs[[2]])$a
#[1] 9

funs[[1]](1)
#[1] 3
funs[[2]](1)
#[1] 9
Comments