ТАК,
Проблема
Это хорошо известно о псевдослучайных числах . «Псевдо» на самом деле означает, что, несмотря на то, что они являются случайными (то есть непредсказуемыми) в целом, они все равно будут одинаковыми в последовательности, в которых использовалось то же самое значение init init. Например, для PHP существует функция mt_srand () . Пример:
mt_srand(1); var_dump(mt_rand(), mt_rand(), mt_rand());
Не важно, сколько раз мы запустим наш скрипт: сгенерированные три числа всегда будут одинаковыми в последовательности.
Теперь моя проблема заключается в том, как сделать то же самое – но для перетасовки массива. Т.е. я хочу создать функцию, которая будет принимать входной массив для перетасовки и семени . В пределах одного и того же семенного значения перетасовка должна иметь последовательный одинаковый порядок. Т.е. позвольте нам называть эту функцию shuffleWithSeed()
– а затем следующее должно работать для каждого запуска скрипта:
$input = ['foo', 'bar', 'baz']; $test = shuffleWithSeed($input, 1000);//1000 is just some constant value var_dump($test); //let it be ['bar', 'foo', 'baz'] $test = shuffleWithSeed($test, 1000); var_dump($test); //let it be ['baz', 'foo', 'bar'] $test = shuffleWithSeed($test, 1000); var_dump($test); //let it be ['baz', 'bar', 'foo'] //...
– независимо от того, сколько раз мы будем делать shuffle для нашего массива – я хочу, чтобы следующая последовательность запуска запуска скрипта всегда была одинаковой в пределах одного seed
значения.
Мой подход
Я имею в виду этот алгоритм:
seed
N
случайных чисел, где N
– число элементов $input
$input
keys. Я реализовал это в:
function shuffleWithSeed(array $input, $seed=null) { if(!isset($seed)) { shuffle($input); return $input; } if(!is_int($seed)) { throw new InvalidArgumentException('Invalid seed value'); } mt_srand($seed); $random = []; foreach($input as $key=>$value) { $random[$key] = mt_rand(); } asort($random); $random = array_combine(array_keys($random), array_values($input)); ksort($random); return $random; }
вfunction shuffleWithSeed(array $input, $seed=null) { if(!isset($seed)) { shuffle($input); return $input; } if(!is_int($seed)) { throw new InvalidArgumentException('Invalid seed value'); } mt_srand($seed); $random = []; foreach($input as $key=>$value) { $random[$key] = mt_rand(); } asort($random); $random = array_combine(array_keys($random), array_values($input)); ksort($random); return $random; }
– теперь также найден алгоритм Фишера-Йейса – но не уверен, что он может работать с псевдослучайными числами (т. е. с семенем)
Вопрос
Как вы можете видеть, я делаю два вида в своей функции – сначала по значениям, а затем по клавишам.
Вот копия и вставка функции, которую я недавно применил для этой цели:
/** * Shuffles an array in a repeatable manner, if the same $seed is provided. * * @param array &$items The array to be shuffled. * @param integer $seed The result of the shuffle will be the same for the same input ($items and $seed). If not given, uses the current time as seed. * @return void */ protected function seeded_shuffle(array &$items, $seed = false) { $items = array_values($items); mt_srand($seed ? $seed : time()); for ($i = count($items) - 1; $i > 0; $i--) { $j = mt_rand(0, $i); list($items[$i], $items[$j]) = array($items[$j], $items[$i]); } }
Он реализует простой перебор Fisher-Yates с генератором случайных чисел.