R
Beginner
1 min read
Vectorised Alternatives and Performance Considerations
Example
# Vectorised vs loop: summing squares
n <- 1e6
x <- seq_len(n)
# Loop version (slow)
loop_sum <- function(x) {
total <- 0
for (val in x) total <- total + val^2
total
}
# Vectorised version (fast)
vec_sum <- function(x) sum(x^2)
# Verify they match
loop_sum(1:10) == vec_sum(1:10) # TRUE
# seq_along() — safe loop index (handles empty vectors)
items <- c("a", "b", "c")
for (i in seq_along(items)) {
cat(i, "->", items[i], "\n")
}
# The 1:length(x) pitfall
empty <- c()
# 1:length(empty) # gives 1 0 — iterates TWICE! Wrong.
seq_along(empty) # integer(0) — correct, zero iterations
# Vectorize() wrapper
scalar_add <- function(x, y) {
if (x > 0) x + y else y
}
vec_add <- Vectorize(scalar_add)
vec_add(c(-1, 2, -3, 4), c(10, 20, 30, 40)) # 10 22 30 44
# Pre-allocation benchmark illustration
slow_grow <- function(n) {
result <- c()
for (i in seq_len(n)) result <- c(result, i^2)
result
}
fast_pre <- function(n) {
result <- numeric(n)
for (i in seq_len(n)) result[i] <- i^2
result
}
# fast_pre is typically 10-100x faster for large n
# Functional replacement for a common loop pattern
# Instead of: for (i in 1:n) result[i] <- f(x[i])
# Prefer: result <- sapply(x, f)
# Or: result <- f(x) when f is already vectorised