I recently answered a question pertaining to for loops. Upon testing my code\'s speed, I noticed that the use of seq() as opposed to :
A more specific reason why it's slower:
seq(x) will call seq.default*, and seq.default calls 1L:x!!
From seq.default:
if ((One <- nargs() == 1L) && !missing(from)) {
lf <- length(from)
return(if (mode(from) == "numeric" && lf == 1L) {
#checks validity -- more slow-down
if (!is.finite(from)) stop("'from' cannot be NA, NaN or infinite")
#boom! under the hood, seq.default is doing 1:N
1L:from
#looks like it defaults to seq_along if length(from) > 1?
} else if (lf) 1L:lf else integer())
}
*Unless, of course, x is Date or POSIXt, or you have another library loaded that has a seq method...
Using seq_len you get nearly the same time as the : operator:
f3 <- function(){
x <- 1:5; y <- numeric(length(x))
for(i in seq_len(length(x))) y[i] <- x[i]^2
y
}
library(microbenchmark)
microbenchmark(f1(), f2(),f3())
Unit: microseconds
expr min lq median uq max neval
f1() 9.988 10.6855 10.9650 11.245 50.704 100
f2() 23.257 23.7465 24.0605 24.445 88.140 100
f3() 10.127 10.5460 10.7555 11.175 18.857 100
Internally seq is doing many verifications before calling : or seq_len.
seq is a generic S3 method, so probably some time is lost dispatching.
seq.default is almost 100 lines long!
You're probably already aware of seq_along, which calls a .Primitive directly and is bit better than 1:length(x) and the best method I have found for long loops:
f3 <- function(){
x <- 1:5; y <- numeric(length(x))
for(i in seq_along(x)) y[i] <- x[i]^2
y
}
> microbenchmark(f1(), f3())
Unit: microseconds
expr min lq median uq max neval
f1() 27.095 27.916 28.327 29.148 89.495 100
f3() 26.684 27.505 27.916 28.327 36.538 100