大概有一个您愿意容忍的最大尺寸;预先分配并填充到该水平,然后在必要时进行修剪。这避免了无法满足双倍大小请求的风险,即使可能只需要少量额外的内存;它很早就失败了,并且只涉及一次而不是 log(n) 重新分配。这是一个具有最大大小的函数、一个生成函数和一个令牌,当没有任何东西可以生成时,生成函数返回该令牌。在返回之前我们最多得到 n 个结果
filln <-
function(n, FUN, ..., RESULT_TYPE="numeric", DONE_TOKEN=NA_real_)
{
results <- vector(RESULT_TYPE, n)
i <- 0L
while (i < n) {
ans <- FUN(..., DONE_TOKEN=DONE_TOKEN)
if (identical(ans, DONE_TOKEN))
break
i <- i + 1L
results[[i]] <- ans
}
if (i == n)
warning("intolerably large result")
else length(results) <- i
results
}
这是一个生成器
fun <- function(thresh, DONE_TOKEN) {
x <- rnorm(1)
if (x > thresh) DONE_TOKEN else x
}
并在行动中
> set.seed(123L); length(filln(10000, fun, 3))
[1] 163
> set.seed(123L); length(filln(10000, fun, 4))
[1] 10000
Warning message:
In filln(10000, fun, 4) : intolerably large result
> set.seed(123L); length(filln(100000, fun, 4))
[1] 23101
我们可以通过与预先知道需要多少空间的东西进行比较来大致对开销进行基准测试
f1 <- function(n, FUN, ...) {
i <- 0L
result <- numeric(n)
while (i < n) {
i <- i + 1L
result[i] <- FUN(...)
}
result
}
这里我们检查单个结果的时间和值
> set.seed(123L); system.time(res0 <- filln(100000, fun, 4))
user system elapsed
0.944 0.000 0.948
> set.seed(123L); system.time(res1 <- f1(23101, fun, 4))
user system elapsed
0.688 0.000 0.689
> identical(res0, res1)
[1] TRUE
对于这个例子来说,这当然被简单的矢量解决方案所掩盖
set.seed(123L); system.time(res2 <- rnorm(23101))
identical(res0, res2)