Make list of functions with lapply

125 views Asked by At

Is there any way to make the following list of functions using lapply? Below, I make a list named "long" the long way. I would like to simplify the code using lapply (or a for loop) but neither seems to work. Thank you.

#This works as expected
long <- list(function(x) x <- within(x, DATE <- as.Date("2013-01-01")),
             function(x) x <- within(x, DATE <- as.Date("2014-01-01")),
             function(x) x <- within(x, DATE <- as.Date("2015-01-01")))

#This does not work
long <- lapply(2013:2015, function(i) x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-"))))

#This does not work
for (i in 2013:2015) long <- list(function(x) x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-"))))
2

There are 2 answers

5
lmo On BEST ANSWER

Maybe the simplest method is to add another function.

long <- lapply(2013:2015,
              function(i) function(x) {
                           x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-")))})

Check that the elements are functions

typeof(long[[1]])
[1] "closure"

Test it

# empty list, x
x <- list()
x <- long[[1]](x)
x
$DATE
[1] "2013-01-01"

As @Roland mentions in the comments, it would be safer to force the evaluation of the i argument.

long <- lapply(2013:2015, function(i) {
                            force(i);
                            function(x) x <- within(x,
                                            DATE <- as.Date(paste(i, "01", "01", sep = "-")))
                           })
5
Hong Ooi On

With some bquote magic:

dates <- c("2013-01-01", "2014-01-01", "2015-01-01")

lapply(dates, function(d) eval(bquote(function(x) within(x, DATE <- as.Date(.(d))))))

#[[1]]
#function (x) 
#within(x, DATE <- as.Date("2013-01-01"))
#<environment: 0x000002b1815ba450>
#
#[[2]]
#function (x) 
#within(x, DATE <- as.Date("2014-01-01"))
#<environment: 0x000002b1815ae320>
#
#[[3]]
#function (x) 
#within(x, DATE <- as.Date("2015-01-01"))
#<environment: 0x000002b1815a1520>

(The assignment x <- within(...) is superfluous inside the function.)

Explanation: bquote creates an unevaluated expression object, with symbols marked out by .(*) replaced by their values. eval then evaluates the expression.

In this case, bquote creates a call to generate a function using function(x) ... with the specific date inserted, so if d has the value "2013-01-01", then bquote(function(x) ... as.Date(.(d)) results in the unevaluated expression function(x) ... as.Date("2013-01-01"). When you call eval on this, the result is a function object containing your desired function body.

See ?eval and ?bquote for more details.