这是一个很好的例子,说明使用sapply比使用循环更低效。尽管使用sapply能让代码看起来更整洁,但你需要用更多的时间来换取这种整洁性。
相反,你可以将while循环包装在for循环中,并封装成一个漂亮简洁的函数。
以下是比较嵌套应用程序循环和嵌套for-while循环的基准测试(还有一个混合应用程序while循环,以确保衡量)。
更新:添加了评论中提到的vapply..match..。比sapply更快,但仍比while循环慢得多。
基准测试:
test elapsed relative
1 for.while 0.069 1.000
2 sapply.while 0.080 1.159
3 vapply.match 0.101 1.464
4 nested.sapply 0.104 1.507
注意,您可以节省三分之一的时间; 当您开始将序列添加到A中时,节省的时间可能会更多。
对于您问题的第二部分:
如果您已经将所有内容都包装在一个不错的函数中,那么将序列添加到A中就很容易了。
A <- c(10, 5, 3, 4, 7, 100, 2)
B <- c(4, 8, 11, 1, 5, 18, 20)
S <- seq(1, 12, 3)
indexesOfB <- t(sapply(S, function(s) findIndx(A+s, B)))
dimnames(indexesOfB) <- list(S, A)
最后,如果您想要找到比A更小的B值,只需在函数中交换操作即可。
(您可以在函数中包含if语句并仅使用一个函数。我认为使用两个单独的函数更加有效率)
findIndx.gt(A, B)
findIndx.lt(A, B)
然后你可以将它包装成一个漂亮的包裹。
rangeFindIndx(A, B, S)
函数
(请注意它们依赖于reshape2
)
rangeFindIndx <- function(A, B, S) {
require(reshape2)
indexesOfB.gt <- sapply(S, function(s) findIndx.gt(A+s, B))
indexesOfB.lt <- sapply(S, function(s) findIndx.lt(A-s, B))
dimnames(indexesOfB.gt) <- dimnames(indexesOfB.gt) <- list(A, S)
gtltMatrix <- cbind(melt(indexesOfB.gt), melt(indexesOfB.lt)$value)
names(gtltMatrix) <- c("A", "S", "indxB.gt", "indxB.lt")
return(gtltMatrix)
}
findIndx.gt <- function(A, B) {
lng <- length(A)
ret <- integer(0)
b <- NULL
for (j in seq(lng-1)) {
i <- j + 1
while (i <= lng && ((b <- B[[i]]) < A[[j]]) ) {
i <- i + 1
}
ret <- c(ret, ifelse(i<lng, i, NA))
}
c(ret, NA)
}
findIndx.lt <- function(A, B) {
lng <- length(A)
ret <- integer(0)
b <- NULL
for (j in seq(lng-1)) {
i <- j + 1
while (i <= lng && ((b <- B[[i]]) > A[[j]]) ) {
i <- i + 1
}
ret <- c(ret, ifelse(i<lng, i, NA))
}
c(ret, NA)
}
apply
循环,因为一旦找到您的值,就没有必要继续搜索。 - Ricardo Saporta