Подтвердить что ты не робот

Рандомизировать массив PHP с семенем?

Я ищу функцию, в которую я могу передать массив и начальное число в PHP и получить "рандомизированный" массив. Если бы я передал тот же массив и то же самое семя снова, я получил бы тот же самый вывод.

Я пробовал этот код

//sample array
$test = array(1,2,3,4,5,6);
//show the array
print_r($test);

//seed the random number generator
mt_srand('123');
//generate a random number based on that
echo mt_rand();
echo "\n";

//shuffle the array
shuffle($test);

//show the results
print_r($test);

Но это не похоже на работу. Есть мысли о том, как это сделать?

Этот вопрос танцует вокруг проблемы, но он старый, и никто не дал фактического ответа о том, как это сделать: могу ли я рандомизировать массив, предоставив начальное число и получив тот же порядок? - "Да, но как?

Обновить

Пока ответы работают с PHP 5.1 и 5.3, но не с 5.2. Так получилось, что машина, на которой я хочу запустить, использует 5.2.

Кто-нибудь может привести пример без использования mt_rand? Он "сломан" в php 5.2, потому что он не даст одинаковую последовательность случайных чисел, основанную на одном и том же семени. Посетите страницу php mt_rand и систему отслеживания ошибок, чтобы узнать об этой проблеме.

4b9b3361

Ответ 1

Вы можете использовать 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.

Ответ 2

Извините, но в соответствии с документацией функция shuffle добавляется автоматически.

Обычно, вы не должны пытаться придумать свои собственные алгоритмы для рандомизации вещей, так как они, скорее всего, будут предвзятыми. Известно, что алгоритм Фишера-Йейтса эффективен и беспристрастен:

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
)

Ответ 3

Проблема заключается в том, что PHP поставляется с двумя генераторами случайных чисел.

Команда shuffle() не использует генератор случайных чисел mt_rand(); он использует более старый генератор случайных чисел rand().

Поэтому, если вы хотите, чтобы shuffle() использовала последовательность семенных чисел, вам нужно выровнять старший рандомизер, используя srand(), а не mt_srand().

В большинстве других случаев вы должны использовать mt_rand(), а не rand(), так как это лучший генератор случайных чисел.

Ответ 4

Основной вопрос состоит из двух частей. Один из них о том, как перетасовать. Другой - о том, как добавить к нему случайность.

Простое решение

Это, вероятно, самый простой ответ на главный вопрос. Достаточно для большинства случаев 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, добавить необходимые методы и ваши предпочтительные формулы. И, поскольку одна и та же функция тасования может использоваться со многими случайными алгоритмами, один случайный алгоритм может использоваться в разных местах.

Ответ 5

В последних версиях PHP семена PHP встроенных функций 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

Просто измените семя, чтобы получить совершенно другую "случайную" последовательность

Ответ 6

Вариант, который также работает с PHP версии 7.2, потому что функция php create_function устарела в самой последней версии php.

mt_srand($seed);

$getMTRand = function () {
    return mt_rand();
};

$order = array_map($getMTRand, range(1, count($array)));
array_multisort($order, $array);
return $array;

Ответ 7

Я думаю, что это сделает работу:

    function choose_X_random_items($original_array , $number_of_items_wanted = -1 , $seed = FALSE ){

//save the keys
foreach ($original_array as $key => $value) {

    $original_array[$key]['key_memory'] = $key;

}

$original_array = array_values($original_array);
$results = array();
if($seed !== FALSE){srand($seed);}
$main_random = rand();
$random = substr($main_random,0,( $number_of_items_wanted == -1 ? count($original_array) : min($number_of_items_wanted,count($original_array)) ));
$random = str_split($random);

foreach ($random AS $id => $value){


    $pick = ($value*$main_random) % count($original_array);
    $smaller_array[] = $original_array[$pick];
    unset($original_array[$pick]);
        $original_array = array_values($original_array);

}


//retrieve the keys
foreach ($smaller_array as $key => $value) {

    $smaller_array[$value['key_memory']] = $value;
    unset($smaller_array[$value['key_memory']]['key_memory']);
    unset($smaller_array[$key]);

}

return $smaller_array;

}

Чтобы не ограничивать результирующий массив, установите для $ number_of_items_wanted значение -1. Чтобы не использовать начальное значение, установите для $ seed значение FALSE.

Ответ 8

Посеянное перемешивание при сохранении индекса ключа:

function seeded_shuffle(array &$items, $seed = false) {

    mt_srand($seed ? $seed : time());

    $keys = array_keys($items);
    $items = array_values($items);

    for ($i = count($items) - 1; $i > 0; $i--) {
        $j = mt_rand(0, $i);
        list($items[$i], $items[$j]) = array($items[$j], $items[$i]);
        list($keys[$i], $keys[$j]) = array($keys[$j], $keys[$i]);
    }

    $items = array_combine($keys, $items);
}

Ответ 9

Это кажется мне самым легким...

srand(123);
usort($array,function($a,$b){return rand(-1,1);});