Pre-Allocating to Improve For Loops

Published

January 19, 2023

How to pre-allocate vectors used in your for loops in R to make your code run faster and perform fewer allocations.

First, set n to be the size of the vector we want to work with

n <- 1e6

Then set up a function that doesn’t pre-allocate a list

no_alloc <- function(n) {

    x <- list()

    for (i in seq_len(n)) {
        x[[i]] <- i
    }

    x
}

Then set up a function that does pre-allocate a list

pre_alloc <- function(n) {
    
    x <- vector(mode = "list", length = n)

    for (i in seq_len(n)) {
        x[[i]] <- i
    }
    
    x
}

And compare the benchmarks for these functions

library(bench)

res <- bench::mark(
    no_alloc(n),
    pre_alloc(n)
)
Warning: Some expressions had a GC in every iteration; so filtering is disabled.
res[c("expression", "min", "median", "itr/sec", "n_gc")]
# A tibble: 2 × 4
  expression        min   median `itr/sec`
  <bch:expr>   <bch:tm> <bch:tm>     <dbl>
1 no_alloc(n)   660.4ms  660.4ms      1.51
2 pre_alloc(n)   60.6ms   64.6ms     12.6 

We can see that pre-allocating is the way to go!