Вот то, что не зависит от рекурсии:
mysample <- function(n, lower, upper, space) {
b <- ceiling((upper - lower + 1)/(space - 1))
bs <- sample(seq(2, b - 1, by = 2), n - 1)
gr <- split(setdiff(1:b,bs), cumsum(c(0, diff(setdiff(1:b, bs))) != 1))
out <- sapply(gr, function(x) (x[1] - 1) * (space - 1) + ceiling(runif(1) * length(x) * (space - 1)))
out[n] <- min(out[n], upper)
out
}
set.seed(123)
min(replicate(min(diff(mysample(100, 1, 100000, 10))), n = 1000))
# [1] 10
mysample
возвращает уже отсортированный последовательность, но, конечно, вы можете использовать sample(mysample(...))
.
Идея функции состоит в том, чтобы разделить интервал [нижний, верхний] на блоки длины space - 1
и на образец n-1
блоков с 2-го, 4-го, 6-го, ... блоков; это будут «запрещенные» блоки, то есть у нас не будет никаких чисел из этих блоков. Затем оставшиеся «разрешенные» блоки могут быть, например, 1, 2, 5; в этом случае мы имеем две группы последовательных блоков (1-й и 2-й, 5-й), и мы отбираем два числа из интервалов, соответствующих этим двум группам блоков. Я также добавил небольшую проверку, превышает ли наибольшее число выше верхнего предела.
Некоторые результаты:
set.seed(123)
upper <- 100000
benchmark(
mysample(100, 1, upper, 10), MichaelChirico(100, 1, upper, 10),
Grothendieck(100, 1, upper, 10), Jonathan(100, 1, upper, 10),
replications = 1, columns = c("test", "relative"))
# test relative
# 3 Grothendieck(100, lower, upper, 10) 1
# 4 Jonathan(100, lower, upper, 10) 344
# 2 MichaelChirico(100, lower, upper, 10) 2133
# 1 mysample(100, lower, upper, 10) 4
upper <- 10000
benchmark(
mysample(100, 1, upper, 10), MichaelChirico(100, 1, upper, 10),
Grothendieck(100, 1, upper, 10), Jonathan(100, 1, upper, 10),
replications = 1, columns = c("test", "relative"))
# test relative
# 3 Grothendieck(100, lower, upper, 10) 132.5
# 4 Jonathan(100, lower, upper, 10) 56.0
# 2 MichaelChirico(100, lower, upper, 10) 27.5
# 1 mysample(100, lower, upper, 10) 1.0
где
MichaelChirico <- function(n, lower, upper, space) {
include <- lower:upper
smpl <- integer(n)
for (i in 1:length(smpl)){
smpl[i] <- si <- sample(include, 1)
include <- setdiff(include, (si - space):(si + space))
}
smpl
}
Grothendieck <- function(n, lower, upper, space) {
repeat {
s <- sample(lower:upper, n)
mindiff <- min(diff(sort(s)))
if (mindiff >= space) break
}
s
}
Jonathan <- function(n, lower, upper, space) {
min_gap <- space
samp_vec <- sample(seq(lower,upper,1), 1)
for (isamp in 1:n) {
possible_new_value <- samp_vec[1]
while(any(abs(samp_vec - possible_new_value) < min_gap)) {
possible_new_value <- sample(seq(lower,upper,1), 1)
}
samp_vec <- c(samp_vec, possible_new_value)
}
samp_vec
}
Я думаю, что этот подход будет очень быстрым для малых (n_desired/n_initial --ie, 100/100000 здесь), но отвергающие часто, как это поднимается.моя страдает из-за другого недостатка - она потерпит неудачу, если у нас закончится доступная ничья (по голубике, это должно произойти, если n_desired> n_initial/10, грубо, но произойдет для подавляющего большинства путей рисования, поскольку n_desired подходы, которые связаны) – MichaelChirico