Randomize un array PHP con un seme?

Sto cercando una funzione che mi può passare un array e un seme in PHP e ottenere un “randomizzati” array. Se ho passato la stessa serie e stessa seme nuovo, vorrei ottenere lo stesso risultato.

Ho provato questo codice

//esempio di array 
$test = array(1,2,3,4,5,6); 
//mostra la matrice 
print_r($prova); 

//generatore di numeri casuali 
mt_srand('123'); 
//genera un numero casuale sulla base di che 
eco mt_rand(); 
echo "\n"; 

//shuffle matrice 
shuffle($prova); 

//mostra i risultati 
print_r($prova); 

Ma non sembra funzionare. Ogni pensiero sul modo migliore per fare questo?

Questa domanda danze intorno al problema ma è vecchio e nessuno ha fornito una risposta concreta su come farlo: Posso randomize un array, fornendo un seme e ottenere lo stesso ordine? – “Sì” – ma come?

Aggiornamento

Le risposte finora PHP 5.1 e 5.3, ma non 5.2. Così succede che la macchina voglio eseguire utilizza 5.2.

Qualcuno può dare un esempio senza l’utilizzo di mt_rand? Si è “rotto” in php 5.2, perché non dare la stessa sequenza di numeri casuali in base al largo lo stesso seme. Vedere la php mt_rand pagina e il bug tracker per ulteriori informazioni su questo problema.

  • Avete notato il changelog qui: php.net/manual/en/function.shuffle.php ? Si dice che a partire da php 4.2.0 non è necessario per inizializzare il generatore di numeri casuali manualmente.
  • Permettetemi di fare sicuro di aver capito ciò che si desidera. Volete un ‘casuale’ array, ma si desidera essere in grado di essere duplicati?
  • Ha bisogno di uno stesso ordine, in modo che egli ha a che fare.
  • Potrebbe essere necessario creare il proprio generatore di numeri casuali e la Matrice di Mescolamento. Guardate a questo link per i dettagli di implementazione: shamimhafiz.wordpress.com
  • Ci sono alcuni grandi risposte. Io non sono sicuro di come scegliere il migliore.
  • Se questa richiesta non è mai accettata, il vostro problema sarà risolto. È sembra essere stato ignorato anche se.

InformationsquelleAutor cwd | 2011-07-02



9 Replies
  1. 19

    È possibile utilizzare array_multisort per ordinare l’array di valori da una seconda serie di mt_rand valori:

    $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);

    Qui $order è un array di mt_rand valori della stessa lunghezza $arr. array_multisort ordina i valori di $order e ordini gli elementi di $arr secondo l’ordine dei valori di $order.

    • Penso che si dispone di $ordine e $arr mista in array_multisort($ordine $arr);
    • No (vedi il primo esempio in array_multisort di riferimento pagina).
    • In effetti forse questa risposta non funziona per tutte le versioni di php. Ho appena notato che un server che esegue 5.2.17 creare una sequenza casuale di numeri per il $variabile dell’ordine. Ho trovato una nota pure qui: Dal 5.2.1 Il Mersenne Twister implementazione in PHP utilizza ora una nuova semina di un algoritmo di Richard Wagner. Identico semi non più in grado di produrre la stessa sequenza di valori che nelle versioni precedenti. Questo comportamento non dovrebbe cambiare di nuovo, ma è considerato pericoloso fare affidamento su di esso comunque. – php.net/manual/en/function.mt-srand.php
    • Quindi probabilmente si deve attaccare al vecchio rand e srand.
    • create_function è stato DEPRECATO come PHP 7.2.0
  2. 45

    Mi dispiace, ma di conseguenza a il
    documentazione
    il
    funzione di riproduzione casuale è seminato automaticamente.

    Normalmente, non provare a venire con i propri algoritmi per rendere le cose dal momento che sono molto suscettibili di essere di parte. Il Fisher-Yates algoritmo è noto per essere efficace e imparziale, però:

    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;
        }
    }

    Esempio (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
    )
    • Esattamente era che stavo cercando. Thx a lot.
    • Provato e funziona
    • Funzione molto utile! Bel lavoro!
    • Questa è una grande soluzione, ma da PHP 5.3.1 la mt_srand “Identici semi non più in grado di produrre la stessa sequenza di valori che nelle versioni precedenti.” – quindi questo non è più un prevedibile shuffle. Ho trovato e usato un Mersenne_Twister classe invece di mt_srand e mt_rand e questo approccio mi ha dato un prevedibile/ripetibili shuffle.
    • Sarà prevedibile, non solo la stessa sequenza come prodotto da versioni di PHP precedenti alla 5.2.1. Ancora degno di nota.
  3. 4

    Il problema è che il PHP è dotato di due generatori di numero casuali, costruito.

    Il shuffle() comando non utilizzare il mt_rand() generatore di numeri casuali; usa il più vecchio rand() generatore di numeri casuali.

    Pertanto, se si desidera shuffle() per l’utilizzo di un teste di serie numero di sequenza, è necessario seme vecchi randomizzatore, utilizzando srand() piuttosto che mt_srand().

    Nella maggior parte dei casi, si dovrebbe utilizzare mt_rand() piuttosto che rand(), dal momento che è un generatore di numeri casuali.

    • hmm, utilizzando srand(123) e quindi la funzione rand() non sembra sempre per produrre lo stesso output php 5.2.17…
  4. 1

    La domanda principale che coinvolge due parti. Uno è su come shuffle. L’altro è su come aggiungere casualità ad esso.

    Una soluzione semplice

    Questa è probabilmente la risposta più semplice alla domanda principale. È sufficiente per la maggior parte dei casi di scripting PHP. Ma non tutti (vedi sotto).

    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;
    }

    Il metodo di cui sopra farà, anche se non produce vera casuale mescola per tutte le possibili semi-serie di combinazioni. Tuttavia, se si vuole veramente di essere equilibrati e tutti, credo PHP shuldn non essere la vostra scelta.

    Più utile una soluzione per i programmatori avanzati

    Come ha dichiarato André Laszlo, la randomizzazione è un’impresa molto difficile. Di solito è meglio lasciare che un dedicato oggetto di gestire. Il mio punto è, che non c’è bisogno di preoccuparsi con la casualità quando si scrive la funzione di riproduzione casuale. A seconda del grado di ramdomness volete nel vostro shuffle, si può avere un numero di Pseudocasuali oggetti tra cui scegliere. Pertanto la sopra potrebbe assomigliare a questo:

    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;
    }

    Ora, questa soluzione è quella che ho io voterei per. Si separa la riproduzione casuale dei codici da codici di randomizzazione. A seconda del tipo di casuale avete bisogno, potete sottoclasse Pseudocasuali, aggiungere la modalità e il vostro preferito formule.
    E, come la stessa funzione shuffle può essere utilizzato con molti casuale algoritmi un algoritmo casuale può essere utilizzato in luoghi diversi.

    • Grazie! Il semplice fatto il trucco per me in cui la risposta scelta si è schiantato a seconda della dimensione della matrice. Molto apprezzato! 🙂
  5. 1

    Una variante che funziona anche con PHP versione 7.2, perché la funzione php create_function è deprecato nella nuova versione di php.

    mt_srand($seed);
    
    $getMTRand = function () {
        return mt_rand();
    };
    
    $order = array_map($getMTRand, range(1, count($array)));
    array_multisort($order, $array);
    return $array;
  6. 0

    Nelle recenti versioni di PHP, semina il PHP builtin rand() e mt_rand() funzioni non darà gli stessi risultati ogni volta. La ragione di questo non è chiaro per me (perchè vuoi seme la funzione in ogni caso, se il risultato è diverso ogni volta.) Comunque, sembra che l’unica soluzione è scrivere la propria funzione random

    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 />';
    }

    Il codice di cui sopra sarà uscita la seguente sequenza ogni volta esecuzione:

    76
    86
    14
    79
    73
    2
    87
    43
    62
    7

    Basta cambiare il seme per ottenere una completamente diversa sequenza “random”

    • Questo algoritmo, un.k.un. Algoritmo 266 (M. C. Pike & I. D. Hill, 1965) è veramente vecchia – e ‘ stato pubblicato nel 1965. Potrebbe non essere “abbastanza casuale”, nel senso che potrebbe essere relativamente facile per qualcuno per predire il prossimo numero generato in base alla precedente uscita del PRNG. Soprattutto perché si tratta di un breve periodo – si avvolge intorno dopo meno di 3 milioni di articoli. Forse un PHP attuazione di Mersenne Twister è un’alternativa migliore?
    • Inoltre, se il seme funzioni non sono più di lavoro è necessario creare uno script per riprodurlo e posta un report di bug. Il problema con il Prng in PHP è che sono stato globale, se un’altra parte di codice, o anche una biblioteca utilizza srand o mt_srand si avranno problemi. Sei sicuro che questo non è ciò che ti succede? In Java o Python, per esempio, è possibile creare un’istanza del PRNG per uso semi diversi per le diverse parti del codice, che è molto meglio, naturalmente.
    • Vedere PHP manca di un moderno RNG.
  7. 0

    Credo che questo farà il lavoro :

        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;
    
    }

    Al fine di non limitare la matrice risultante, set $number_of_items_wanted a -1
    Per non utilizzare un seme, l’insieme $seme di FALSE

  8. 0

    Seminato shuffle, pur mantenendo la chiave indice:

    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);
    }

Lascia un commento