Я хотел бы случайным образом перебирать диапазон. Каждое значение будет посещено только один раз, и в конечном итоге будут посещены все значения. Например:
class Array
def shuffle
ret = dup
j = length
i = 0
while j > 1
r = i + rand(j)
ret[i], ret[r] = ret[r], ret[i]
i += 1
j -= 1
end
ret
end
end
(0..9).to_a.shuffle.each{|x| f(x)}
где f(x)
— некоторая функция, которая работает с каждым значением. перетасовка Фишера-Йейтса используется для эффективного обеспечения случайного порядка.
Моя проблема в том, что shuffle
нужно работать с массивом, что не очень хорошо, потому что я работаю с астрономически большими числами. Ruby быстро потребляет большое количество оперативной памяти, пытаясь создать чудовищный массив. Представьте себе замену (0..9)
на (0..99**99)
. Вот почему следующий код не будет работать:
tried = {} # store previous attempts
bigint = 99**99
bigint.times {
x = rand(bigint)
redo if tried[x]
tried[x] = true
f(x) # some function
}
Этот код очень наивен и быстро исчерпывает память, так как tried
получает больше записей.
Какой алгоритм может выполнить то, что я пытаюсь сделать?
[Edit1]: Почему я хочу это сделать? Я пытаюсь исчерпать пространство поиска хеш-алгоритма для входной строки N-длины, ищущей частичные коллизии. Каждое число, которое я генерирую, эквивалентно уникальной входной строке, энтропии и всему остальному. По сути, я «подсчитываю», используя пользовательский алфавит а>.
[Edit2]: это означает, что f(x)
в приведенных выше примерах — это метод, который создает хэш и сравнивает его с постоянным целевым хэшем для частичных конфликтов. Мне не нужно сохранять значение x
после вызова f(x)
, поэтому память должна оставаться неизменной с течением времени.
[Edit3/4/5/6]: дополнительные разъяснения/исправления.
[Решение]. Следующий код основан на решении @bta. Для краткости next_prime
не показан. Он производит приемлемую случайность и посещает каждое число только один раз. См. фактический пост для более подробной информации.
N = size_of_range
Q = ( 2 * N / (1 + Math.sqrt(5)) ).to_i.next_prime
START = rand(N)
x = START
nil until f( x = (x + Q) % N ) == START # assuming f(x) returns x
(0..9).sort_by{rand}.map{|x| f(x)}
, чтобы использоватьeach
вместоmap
. Это сделает вопрос более ясным. - person Harish Shetty   schedule 18.03.2010sort_by rand
тоже не правильно; это даст необъективные результаты. См. robweir.com/blog/2010/02/microsoft. -random-browser-ballot.html (JavaScript, но та же концепция). - person Matthew Flaschen   schedule 18.03.2010