get random value from a PHP array, but make it uni

2019-03-27 13:58发布

问题:

I want to select a random value from a array, but keep it unique as long as possible.

For example if I'm selecting a value 4 times from a array of 4 elements, the selected value should be random, but different every time.

If I'm selecting it 10 times from the same array of 4 elements, then obviously some values will be duplicated.

I have this right now, but I still get duplicate values, even if the loop is running 4 times:

$arr = $arr_history = ('abc', 'def', 'xyz', 'qqq');

for($i = 1; $i < 5; $i++){
  if(empty($arr_history)) $arr_history = $arr; 
  $selected = $arr_history[array_rand($arr_history, 1)];  
  unset($arr_history[$selected]); 
  // do something with $selected here...
}

回答1:

You almost have it right. The problem was the unset($arr_history[$selected]); line. The value of $selected isn't a key but in fact a value so the unset wouldn't work.

To keep it the same as what you have up there:

<?php

$arr = $arr_history = array('abc', 'def', 'xyz', 'qqq');

for ( $i = 1; $i < 10; $i++ )
{
  // If the history array is empty, re-populate it.
  if ( empty($arr_history) )
    $arr_history = $arr;

  // Select a random key.
  $key = array_rand($arr_history, 1);

  // Save the record in $selected.
  $selected = $arr_history[$key];

  // Remove the key/pair from the array.
  unset($arr_history[$key]);

  // Echo the selected value.
  echo $selected . PHP_EOL;
}

Or an example with a few less lines:

<?php

$arr = $arr_history = array('abc', 'def', 'xyz', 'qqq');

for ( $i = 1; $i < 10; $i++ )
{
  // If the history array is empty, re-populate it.
  if ( empty($arr_history) )
    $arr_history = $arr;

  // Randomize the array.
  array_rand($arr_history);

  // Select the last value from the array.
  $selected = array_pop($arr_history);

  // Echo the selected value.
  echo $selected . PHP_EOL;
}


回答2:

How about shuffling the array, and popping items off.

When pop returns null, reset the array.

$orig = array(..);
$temp = $orig;
shuffle( $temp );

function getNextValue()
{
  global $orig;
  global $temp;

  $val = array_pop( $temp );

  if (is_null($val))
  {
    $temp = $orig;
    shuffle( $temp );
    $val = getNextValue();
  }
  return $val;
}

Of course, you'll want to encapsulate this better, and do better checking, and other such things.



回答3:

Php has a native function called shuffle which you could use to randomly order the elements in the array. So what about this?

$arr = ('abc', 'def', 'xyz', 'qqq');

$random = shuffle($arr);

foreach($random as $number) {
    echo $number;
}


回答4:

http://codepad.org/sBMEsXJ1

<?php

    $array = array('abc', 'def', 'xyz', 'qqq');

    $numRandoms = 3;

    $final = array();

    $count = count($array);

    if ($count >= $numRandoms) {

        while (count($final) < $numRandoms) {

            $random = $array[rand(0, $count - 1)];

            if (!in_array($random, $final)) {

                array_push($final, $random);
            }
        }
    }

    var_dump($final);

?>


回答5:

key != value, use this:

$index = array_rand($arr_history, 1);
$selected = $arr_history[$index];  
unset($arr_history[$index]); 


回答6:

I've done this to create a random 8 digit password for users:

$characters = array(
    "A","B","C","D","E","F","G","H","J","K","L","M",
    "N","P","Q","R","S","T","U","V","W","X","Y","Z",
    "a","b","c","d","e","f","g","h","i","j","k","m",
    "n","p","q","r","s","t","u","v","w","x","y","z",
    "1","2","3","4","5","6","7","8","9");

for( $i=0;$i<=8;++$i ){
    shuffle( $characters );
    $new_pass .= $characters[0];
}


回答7:

If you do not care about what particular values are in the array, you could try to implement a Linear Congruential Generator to generate all the values in the array.

LCG implementation

Wikipedia lists some values you can use, and the rules to select the values for the LCG algorithm, because the LCG algorith is deterministic it is guaranteed not to repeat a single value before the length of the period.

After filling the array with this unique numbers, you can simply get the numbers in the array 1 by 1 in order.



回答8:

Easy and clean:

$colors = array('blue', 'green', 'orange');
$history = $colors;

function getColor($colors, &$history){
    if(count($history)==0)
        $history = $colors;
    return array_pop( $history );
}

echo getColor($colors, $history);