rand - Aleatorizar una matriz de PHP con una semilla?
rand php sin repetir (7)
Estoy buscando una función a la que pueda pasar una matriz y una semilla en PHP y obtener una matriz "aleatorizada". Si pasara la misma matriz y la misma semilla nuevamente, obtendría el mismo resultado.
He intentado este código
//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);
pero no parece funcionar. ¿Alguna idea sobre la mejor manera de hacer esto?
Esta pregunta gira alrededor del tema, pero es antigua y nadie ha proporcionado una respuesta real sobre cómo hacerlo: ¿puedo aleatorizar un conjunto proporcionando una semilla y obtengo el mismo pedido? - "¿Si pero como?
Actualizar
Las respuestas hasta ahora funcionan con PHP 5.1 y 5.3, pero no con 5.2. Simplemente sucede que la máquina en la que quiero ejecutar esto está usando 5.2.
¿Alguien puede dar un ejemplo sin usar mt_rand? Está "roto" en PHP 5.2 porque no dará la misma secuencia de números aleatorios basados en la misma semilla. Consulte la página php mt_rand y el rastreador de errores para obtener más información sobre este tema.
Lo sentimos, pero de acuerdo con la documentación, la función de reproducción aleatoria se siembra automáticamente.
Normalmente, no debes tratar de crear tus propios algoritmos para aleatorizar las cosas, ya que es muy probable que sean parciales. Sin embargo, se sabe que el algorithm Fisher-Yates es eficiente e imparcial:
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;
}
}
Ejemplo (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
)
El problema que tienes es que PHP viene con dos generadores de números aleatorios integrados.
El comando shuffle()
no usa el generador de números aleatorios mt_rand()
; usa el generador de números aleatorios rand()
más antiguo.
Por lo tanto, si desea que shuffle()
use una secuencia numérica sembrada, debe mt_srand()
el aleatorizador anterior, utilizando srand()
lugar de mt_srand()
.
En la mayoría de los demás casos, debe usar mt_rand()
lugar de rand()
, ya que es un generador de números aleatorios mejor.
En versiones recientes de PHP, sembrar las funciones mt_rand()
PHP rand()
y mt_rand()
no le dará los mismos resultados cada vez. La razón de esto no está clara para mí (¿por qué querría sembrar la función de todos modos si el resultado es diferente cada vez)? De todos modos, parece que la única solución es escribir su propia función aleatoria
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;
}
}
Uso:
// set seed
Random::seed(42);
// echo 10 numbers between 1 and 100
for ($i = 0; $i < 10; $i++) {
echo Random::num(1, 100) . ''<br />'';
}
El código anterior dará como resultado la siguiente secuencia cada vez que lo ejecute:
76
86
14
79
73
2
87
43
62
7
Simplemente cambie la semilla para obtener una secuencia "aleatoria" completamente diferente
Esto parece el más fácil para mí ...
srand(123);
usort($array,function($a,$b){return rand(-1,1);});
La pregunta principal tiene dos partes. Una es sobre cómo mezclar. El otro es acerca de cómo agregarle aleatoriedad.
Una solución simple
Esta es probablemente la respuesta más simple a la pregunta principal. Es suficiente para la mayoría de los casos en PHP scripting. Pero no todos (ver abajo).
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;
}
El método anterior funcionará, aunque no produzca mezclas aleatorias verdaderas para todas las posibles combinaciones de matriz de semillas. Sin embargo, si realmente quieres que sea equilibrado y todo, supongo que PHP no será tu elección.
Una solución más útil para programadores avanzados
Como afirma André Laszlo, la aleatorización es un asunto complicado. Por lo general, es mejor dejar que un objeto dedicado lo maneje. Mi punto es que no deberías molestarte con la aleatoriedad cuando escribas la función de mezcla. Dependiendo del grado de ramdomness que desee en su barajado, puede tener una cantidad de objetos PseudoRandom para elegir. Por lo tanto, lo anterior podría verse así:
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;
}
Ahora, esta es la solución por la que votaría. Separa los códigos aleatorios de los códigos de aleatorización. Dependiendo del tipo de al azar que necesite, puede subclasificar PseudoRandom, agregar los métodos necesarios y sus fórmulas preferidas. Y, como la misma función de mezcla se puede usar con muchos algoritmos aleatorios, se puede usar un algoritmo aleatorio en diferentes lugares.
Una variante que también funciona con PHP versión 7.2, porque la función php create_function está en desuso en la versión php más reciente.
mt_srand($seed);
$getMTRand = function () {
return mt_rand();
};
$order = array_map($getMTRand, range(1, count($array)));
array_multisort($order, $array);
return $array;
Puede usar array_multisort
para ordenar los valores de matriz mediante una segunda matriz de valores 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);
Aquí $order
es una matriz de mt_rand
valores de la misma longitud que $arr
. array_multisort
ordena los valores de $order
y ordena los elementos de $arr
según el orden de los valores de $order
.