Вот еще один способ приблизиться к этому.
Наименьшие цифры можно делать:
a = Array.new(5) { |i| i * 3 + 1 }
#=> [1, 4, 7, 10, 13]
Мы можем увеличивать эти цифры (или эту группу номеров) 100 - 13 = 87 раз, пока мы не попали в конец:
87.times { a[0..-1] = a[0..-1].map(&:next) }
a #=> [88, 91, 94, 97, 100]
Это максимально допустимые числа.
Вместо приращения всех элементов, мы можем выбрать случайный элемент каждый раз, и приращение, что один (и это правильно соседи):
def spread(size, count, step)
arr = Array.new(count) { |i| i * step + 1 }
(size - arr.last).times do
i = rand(0..arr.size)
arr[i..-1] = arr[i..-1].map(&:next)
end
arr
end
5.times do
p spread(100, 5, 3)
end
Выход:
[21, 42, 56, 73, 86]
[6, 21, 45, 61, 81]
[20, 33, 48, 63, 81]
[12, 38, 55, 75, 90]
[11, 29, 50, 71, 86]
[26, 44, 64, 79, 95]
К сожалению, мы должны циклу несколько раз для получения окончательных значений. Это не только медленно, но и приводит к распределению неравномерной:
Было бы лучше, чтобы определить 6 случайных смещений, что сумма в 87 и перемещать элементы соответственно. Почему 6? Поскольку смещения являются расстояниями между нашими 5 числами, т. Е.: Метод
n1 n2 n3 n4 n5
|<-o1->|<--o2-->|<-------o3------->|<-o4->|<----o5---->|<----o6---->|
0 max
Этот помощник возвращает такие смещения: (украдено из here)
def offsets(size, count)
offsets = Array.new(count) { rand(0..size) }.sort
[0, *offsets, size].each_cons(2).map { |a, b| b - a }
end
o = offsets(87, 5) #=> [3, 0, 15, 4, 64, 1]
o.inject(:+) #=> 87
Мы можем добавить смещения к нашему исходному массиву номер:
def spread(size, count, step)
arr = Array.new(count) { |i| i * step }
offsets(size - arr.last, count).each_with_index do |offset, index|
arr[index..-1] = arr[index..-1].map { |i| i + offset }
end
arr
end
5.times do
p spread(99, 5, 3)
end
Выход:
[1, 14, 48, 60, 94]
[12, 46, 54, 67, 72]
[8, 14, 35, 40, 45]
[27, 30, 51, 81, 94]
[63, 79, 86, 90, 96]
Как и следовало ожидать, это приводит к случайному распределению:
Это выглядит лучше. Обратите внимание, что эти результаты основаны на нуле.
Мы можем даже удалить начальный массив и рассчитать окончательные значения из смещений. Начиная с первого смещения, нам просто нужно добавить каждое следующее смещение плюс 3:
def spread(size, count, step)
offs = offsets(size - (count - 1) * step, count)
(1...offs.size).each { |i| offs[i] += offs[i-1] + step }
offs[0, count]
end
Должно ли это быть возрастающей последовательностью? Имеют ли только последовательные цифры? Является ли '[1, 4, 1, 4, 1]' okay (при условии, что он был создан случайным образом? – sawa
Что такое случайная последовательность в этом случае? Я могу представить два способа рисования случайного набора чисел M между 1 и N так что никакие два числа не находятся внутри D друг от друга. Первый - перечислить все такие наборы чисел, а затем выбрать один случайным образом. (В зависимости от N, M и D может быть довольно много наборов.) Второй способ было бы случайным образом нарисовать числа N, а затем проверить, не находится ли какая-либо пара внутри D друг от друга. Если нет, у вас есть случайное множество, если это так, отбросьте набор и нарисуйте еще один случайный набор из N, продолжая до тех пор, пока не пройдет множество test (cont ...) –
(... продолжение) Опять же, это может занять некоторое время. (Все зависит от значений трех параметров.) Оба этих метода приводят к случайному набору. Если, однако, оба этих подхода являются вычислительно неосуществимыми, и вы прибегаете к какой-либо процедуре * ad hoc *, вы, вероятно, не будете рисовать набор случайным образом и не поймут, как может быть искажен ваш образец. –