Here's an example that shows how slow it can be to modify a list in-place using a for-loop:
item_names <- paste0("item", 1:20000)
# Measure the time to evaluate the expression
system.time( {
x <- list()
for (name in item_names) {
x[[name]] <- 0
}
})
# user system elapsed
# 4.928 0.764 5.711
Assigning 20,000 items to a list this way takes about 5 seconds.
What about environments? Unlike lists, environments aren't copied on write, so they don't slow down when modifying them in-place:
system.time( {
e <- new.env()
for (name in item_names) {
e[[name]] <- 0
}
})
# user system elapsed
# 0.054 0.000 0.054
# environments don't preserve order, so they won't be identical
identical(x, as.list(e))
# [1] FALSE
You can actually generate a list in one go using lapply instead of a for loop, and this is much faster since the list isn't being modified in place (and thus being copied many times):
system.time( {
# Create a named vector to use as the source of the lapply
vec <- numeric(length(item_names))
names(vec) <- item_names
# Generate a new list using lapply
y <- lapply(vec, function(x) 0)
})
# user system elapsed
# 0.005 0.000 0.005
# Exactly the same result as the original version
identical(x, y)
# [1] TRUE
You might think, maybe it's the lapply that makes this last example really fast -- perhaps the for-loop used in the first two versions is slower than the lapply used in the third. But actually, lapply is slightly slower than a for-loop. The speed advantage of an lapply is that it collects the output into a list -- if you instead do the list assignments in a loop, it can be an expensive operation, as shown in the first example.
To illustrate: the next example uses an environment (like the second example) and it uses lapply (like the third example) but the lapply is simply being used to assign items in an environment; it's not being used to collect the output.
# Speed with lapply instead of for loop is slightly slower
system.time({
e2 <- new.env()
lapply(names, function(name) {
e2[[name]] <- 0
})
})
# user system elapsed
# 0.072 0.000 0.072