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

2019-03-27 13:25发布

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

8条回答
在下西门庆
2楼-- · 2019-03-27 13:40

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;
}
查看更多
forever°为你锁心
3楼-- · 2019-03-27 13:47

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.

查看更多
祖国的老花朵
4楼-- · 2019-03-27 13:50

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.

查看更多
聊天终结者
5楼-- · 2019-03-27 13:53

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

?>
查看更多
祖国的老花朵
6楼-- · 2019-03-27 13:56

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);
查看更多
Animai°情兽
7楼-- · 2019-03-27 13:59

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];
}
查看更多
登录 后发表回答