之前的所有解决方案都隐式检查向量的每个元素。正如@Robert Kubrick 指出的那样,这并没有利用向量已经排序的事实。
为了利用向量的排序特性,您可以使用二分搜索(通过findInterval
)来查找开始和结束索引,而无需查看每个元素:
n<-1e9
v<--3:(n+3)
system.time(a <- v [v>=1 & v <=n]) # 68 s
system.time(b <- v[do.call(seq,as.list(findInterval(c(1,n),v)))]) # 15s
identical(a,b) # TRUE
它有点笨拙,并且有一些讨论认为二进制搜索findInterval
可能不是完全有效的,但总体思路是存在的。
正如评论中所指出的,上述仅在索引位于向量中时才有效。这是我认为可行的功能:
in.range <- function(x, lo = -Inf, hi = +Inf) {
lo.idx <- findInterval(lo, x, all.inside = TRUE)
hi.idx <- findInterval(hi, x)
lo.idx <- lo.idx + x[lo.idx] >= lo
x[seq(lo.idx, hi.idx)]
}
system.time(b <- in.range(v, 1, n) # 15s