#php #arrays #multidimensional-array #shuffle #entropy
#php #массивы #многомерный массив #перетасовка #энтропия
Вопрос:
Мне нужно перетасовать массив на основе начального числа, чтобы я мог получить ту же перетасовку, если мне это нужно.
Например:
1. print_r( shuffleIt( $array, 2 ) );
2. print_r( shuffleIt( $array, 6 ) );
3. print_r( shuffleIt( $array, 2 ) );
- и 3. будет отображаться тот же перетасованный массив, но отличный от 2.
Я нашел эту функцию в Google:
function entropy( $array, $sort_seed ) {
mt_srand( $sort_seed );
$order = array_map( create_function( '$val', 'return mt_rand( );' ), range( 1, count( $array ) ) );
array_multisort( $order, $array );
return $array;
}
Он отлично работает на моем компьютере с php-cli, я всегда получаю один и тот же массив для каждого используемого мной sort_seed, но когда я загружаю его на сервер, я получаю разные массивы каждый раз, даже когда я использую один и тот же sort_seed.
Как я мог бы всегда получать один и тот же перетасованный массив при использовании одного и того же sort_seed ?
кстати. Мне нужно сохранить ключи или отсортировать многомерный массив, чтобы я мог хранить там ключ.
Комментарии:
1. Итак, вы используете
mt_rand
mt_srand
для создания порядка, который всегда одинаков, если$seed
он одинаков?2. @hakre Порядок всегда одинаков только на моем компьютере, а не на сервере, я не создавал функцию.
3. Я понял вашу проблему с этой функцией. Но о чем вы заботитесь? Каждый компьютер имеет свой собственный генератор случайных чисел, поэтому он отличается на разных компьютерах. То, что вы описываете, просто нормально. Но что вы ищете?
4. @hakre Да, поэтому я ищу альтернативу, чтобы я мог получить тот же перетасованный массив на основе числа на любом компьютере.
Ответ №1:
Если вам это нужно на любом ПК, вам нужен генератор случайных чисел, который работает одинаково на всех компьютерах. Я посмотрел один генератор псевдослучайных чисел, который может вам подойти, на странице Википедии «Генерация случайных чисел» и поместил его в класс, чтобы вы могли его заполнить.
Я не знаю, для чего вам это нужно, но это может удовлетворить ваши потребности. Это не зависит от конфигурации системы:
function shuffleIt($array, $seed)
{
$mwc = new mwc($seed);
$order = array();
$count = count($array);
while($count--)
$order[] = $mwc->random()
;
array_multisort($order, $array);
return $array;
}
/**
* Multiply-with-carry RNG
*
* method invented by George Marsaglia
*/
class mwc
{
private static $def_m_w = 1712; /* must not be zero */
private static $def_m_z = 23; /* must not be zero */
private $m_w, $m_z;
public function __construct($seed = NULL)
{
$this->m_w = self::$def_m_w;
$this->m_z = self::$def_m_z;
if (NULL !== $seed)
$this->seed($seed);
}
public function seed($seed)
{
$seed = (int) $seed;
if (!$seed) throw new InvalidArgumentException('Must not be zero.');
$this->m_z = $seed;
$this->random();
}
public function random()
{
$this->m_z = 36969 * ($this->m_z amp; 65535) ($this->m_z >> 16);
$this->m_w = 18000 * ($this->m_w amp; 65535) ($this->m_w >> 16);
return ($this->m_z << 16) $this->m_w; /* 32-bit result */
}
}
Примечание: это может вести себя по-разному в 32/64-разрядных системах, тем более что PHP отличается здесь для целых чисел и переполнений между Windows и unix. Возможно, вам потребуется смещение на минимум со знаком для 32-битных целых чисел в PHP вместо 0, как сейчас, чтобы переключить реализацию на gmp или просто уменьшить размер на один бит.
Пример использования 32 бит, о котором сообщила ekke из Нидерландов
$shuffle = new GeorgeShuffle();
$seed = $shuffle->seed();
$a = array('A', 'B', 'C', 'D', 'E', 'F', 'G');
$shuffle->reOrder($a);
var_dump($a);
$shuffle->seed($seed);
$shuffle->reOrder($a);
var_dump($a);
/**
* Array shuffle class using
* the multiply-with-carry method
* invented by George Marsaglia
*/
class GeorgeShuffle
{
private static $def_m_w = 1959; /* must not be zero */
private static $def_m_z = 2006; /* must not be zero */
private $m_w, $m_z;
const maxint = 2147483647;
public function __construct($seed = null)
{
$this->m_w = self::$def_m_w;
$this->m_z = self::$def_m_z;
if ($seed) $this->seed($seed);
}
public function reOrder(amp;$array, $seed = null)
{
if (!empty($seed)) $this->seed($seed);
$a = array();
for ($i = 0, $j = count($array); $i < $j; $i ) {
$a[$i] = $this->random();
}
array_multisort($a, $array);
//- to return a copy, remove the amp;
return $array;
}
public function seed($seed = false)
{
if (is_string($seed)) $seed = hexdec($seed);
if (empty($seed)) $seed = round(mt_rand(1, self::maxint));
$this->m_z = $seed;
$this->random();
//- return the seed used in hex (8 chars) for reproducing
return str_pad(dechex($seed), 8, '0', STR_PAD_LEFT);
}
public function random()
{
$this->m_z = 36969 * (($this->m_z And 65535) ($this->m_z >> 16));
$this->m_w = 18000 * (($this->m_w And 65535) ($this->m_w >> 16));
return ($this->m_z << 16) $this->m_w; /* 32-bit signed result */
}
}
Комментарии:
1. вау, просто потрясающе. Спасибо, чувак.
Ответ №2:
Случайно ли у вас на хосте запущено расширение безопасности Suhosin? По-видимому, у него есть пара директив, которые не позволяют сценариям устанавливать начальное значение:
suhosin.srand.ignore = On
suhosin.mt_srand.ignore = On
Дальнейшее чтение:
- http://www.suspekt.org/2008/08/22/suhosin-0926-improved-randomness/
- http://www.adayinthelifeof.nl/2010/12/13/php-srand-problems-with-suhosin/
Вот быстрый способ проверить, является ли это проблемой:
<?php
mt_srand(33);
var_dump(mt_rand(1, 10000));
mt_srand(33);
var_dump(mt_rand(1, 10000));
mt_srand(33);
var_dump(mt_rand(1, 10000));
Комментарии:
1. Я понимаю, что mt_rand не будет выполнять эту работу, но что я могу использовать, чтобы перетасовать массив на основе номера ключа и получить тот же результат на любом ПК?
2. Кажется, я неправильно понял ваш вопрос. Предложение «Я получаю разные массивы каждый раз, даже когда я использую один и тот же sort_seed» предполагает совершенно другую вещь: (