14.5 Functionals vs. Loops
The higher-order functions we have studied in this chapter are often called functionals. As we pointed out earlier, they deliver results that could have been produced by a writing a loop of some sort.
Once you get used to functionals, you will find that they are often more “expressive” than loops—easier for others to read and to understand, and less prone to bugs. Also, many of them are optimized by the developers of R to run a bit faster than an ordinary loop written in R.
For example, consider the following list. It consists of ten thousand vectors, each of which contains 100 randomly-generated numbers.
<- map(rep(100, 10000), runif) lst
If we want the mean of each vector, we could write a loop:
<- numeric(10000)
means for ( i in 1:10000 ) {
<- mean(lst[[i]])
means[i] }
Or we could use map_dbl()
:
<- map_dbl(lst, mean) means
Comparing the two using system.time()
, on my machine I got:
system.time(means <- map_dbl(lst, mean))
## user system elapsed
## 1.557 0.073 1.630
For the loop, I get:
system.time({
<- numeric(10000)
means for ( i in 1:10000 ) {
<- mean(lst[[i]])
means[i]
} })
## user system elapsed
## 1.653 0.075 1.730
The map-function is a bit faster, but the difference is small.
Remember also that vectorization is much faster than looping, and is also usually quite expressive, so don’t struggle to take a functional approach when vectorization is possible. (This advice applies to a several examples from this Chapter, in which the desired computations had already been accomplished in earlier chapters by some form of vectorization.)