Я ищу функцию, через которую я могу передать массив и семя в PHP и получить «рандомизированный» массив. Если бы я снова передал один и тот же массив и одно и то же семя, я бы получил тот же результат.
Я пробовал этот код
// образец массива $ test = array (1,2,3,4,5,6); // показать массив print_r ($ тест); // засеваем генератор случайных чисел mt_srand ( '123'); // генерируем случайное число, основанное на этом echo mt_rand (); echo "\ n"; // перетасовывать массив перетасовка ($ тест); // показать результаты print_r ($ тест);
Но, похоже, это не работает. Любые мысли о лучшем способе сделать это?
Этот вопрос танцует вокруг проблемы, но он старый, и никто не дал фактического ответа о том, как это сделать: могу ли я рандомизировать массив, предоставив семя и получив тот же порядок? – "Да, но как?
Ответы до сих пор работают с PHP 5.1 и 5.3, но не с 5.2. Просто так, что машина, на которой я хочу запустить эту функцию, использует 5.2.
Может ли кто-нибудь привести пример без использования mt_rand? Он «сломан» в php 5.2, потому что он не будет давать одну и ту же последовательность случайных чисел, основанных на одном семени. См. Страницу php mt_rand и отслеживатель ошибок, чтобы узнать об этой проблеме.
Вы можете использовать array_multisort
для упорядочения значений массива вторым массивом значений mt_rand
:
$arr = array(1,2,3,4,5,6); mt_srand('123'); $order = array_map(create_function('$val', 'return mt_rand();'), range(1, count($arr))); array_multisort($order, $arr); var_dump($arr);
Здесь $order
– массив значений mt_rand
той же длины, что и $arr
. array_multisort
сортирует значения $order
и заказывает элементы $arr
соответствии с порядком значений $order
.
Извините, но в соответствии с документацией функция перетасовки автоматически загружается.
Как правило, вы не должны пытаться придумать свои собственные алгоритмы для рандомизации вещей, поскольку они, скорее всего, будут предвзятыми. Известно, что алгоритм Фишера-Йейса эффективен и беспристрастен:
function fisherYatesShuffle(&$items, $seed) { @mt_srand($seed); for ($i = count($items) - 1; $i > 0; $i--) { $j = @mt_rand(0, $i); $tmp = $items[$i]; $items[$i] = $items[$j]; $items[$j] = $tmp; } }
Пример (PHP 5.5.9):
php > $original = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); php > $shuffled = (array)$original; php > fisherYatesShuffle($shuffled, 0); php > print_r($shuffled); Array ( [0] => 6 [1] => 0 [2] => 7 [3] => 2 [4] => 9 [5] => 3 [6] => 1 [7] => 8 [8] => 5 [9] => 4 ) php > $shuffled = (array)$original; php > fisherYatesShuffle($shuffled, 0); php > print_r($shuffled); Array ( [0] => 6 [1] => 0 [2] => 7 [3] => 2 [4] => 9 [5] => 3 [6] => 1 [7] => 8 [8] => 5 [9] => 4 )
Проблема в том, что PHP поставляется с двумя генераторами случайных чисел.
Команда shuffle()
не использует генератор случайных чисел mt_rand()
; он использует генератор случайных чисел rand()
.
Поэтому, если вы хотите, чтобы shuffle()
использовал последовательность серированных чисел, вам нужно mt_srand()
старший рандомизатор, используя srand()
а не mt_srand()
.
В большинстве других случаев вы должны использовать mt_rand()
а не rand()
, так как это лучший генератор случайных чисел.
Основной вопрос состоит из двух частей. Один из них о том, как перетасовать. Другой – о том, как добавить к нему случайность.
Вероятно, это самый простой ответ на главный вопрос. Достаточно для большинства случаев PHP-скриптов. Но не все (см. Ниже).
function /*array*/ seedShuffle(/*one dimentional array*/ $array, /*integer*/ $seed) { $tmp = array(); for ($rest = $count = count($array);$count>0;$count--) { $seed %= $count; $t = array_splice($array,$seed,1); $tmp[] = $t[0]; $seed = $seed*$seed + $rest; } return $tmp; }
Вышеупомянутый метод будет действовать, даже если он не создает настоящие случайные перетасовки для всех возможных комбинаций семенных массивов. Однако, если вы действительно хотите, чтобы он был сбалансированным и все, я думаю, PHP не будет вашим выбором.
Как заявил Андре Ласло, рандомизация – сложный бизнес. Как правило, лучше всего позволить выделенному объекту обрабатывать его. Я хочу сказать, что вам не нужно беспокоиться о случайности, когда вы пишете функцию тасования. В зависимости от того, какую степень ramdomness вы хотели бы в вашем тасовании, у вас может быть несколько объектов PseudoRandom на выбор. Таким образом, вышесказанное может выглядеть так:
abstract class PseudoRandom { protected abstract function /*integer*/ nextInt(); public function /*integer*/ randInt(/*integer*/ $limit) { return $this->nextInt()%$limit; } } function /*array*/ seedShuffle($array, /*PseudoRandom Object*/ $rnd) { $tmp = array(); $count = count($array); while($count>0) { $t = array_splice($array,$rnd->randInt($count--),1); $tmp[] = $t[0]; } return $tmp; }
Теперь это решение – это то, за что я проголосую. Он отделяет коды тасования от кодов рандомизации. В зависимости от того, какое именно случайное значение вам нужно, вы можете подклассировать PseudoRandom, добавить необходимые методы и ваши предпочтительные формулы. И, поскольку одна и та же функция тасования может использоваться со многими случайными алгоритмами, один случайный алгоритм может использоваться в разных местах.
В последних версиях PHP mt_rand()
функций PHP builtin rand()
и mt_rand()
не дают вам одинаковых результатов каждый раз. Причина для этого мне не ясна (почему вы хотите, чтобы вы все равно семени, если результат каждый раз отличается.) В любом случае, похоже, единственное решение – написать свою собственную случайную функцию
class Random { // random seed private static $RSeed = 0; // set seed public static function seed($s = 0) { self::$RSeed = abs(intval($s)) % 9999999 + 1; self::num(); } // generate random number public static function num($min = 0, $max = 9999999) { if (self::$RSeed == 0) self::seed(mt_rand()); self::$RSeed = (self::$RSeed * 125) % 2796203; return self::$RSeed % ($max - $min + 1) + $min; } }
Применение:
// set seed Random::seed(42); // echo 10 numbers between 1 and 100 for ($i = 0; $i < 10; $i++) { echo Random::num(1, 100) . '<br />'; }
В приведенном выше коде будет выводиться следующая последовательность при каждом запуске:
76 86 14 79 73 2 87 43 62 7
Просто измените семя, чтобы получить совершенно другую «случайную» последовательность
Это кажется мне самым легким …
srand(123); usort($array,function($a,$b){return rand(-1,1);});