получите случайное значение из массива PHP, но сделайте его уникальным

Я хочу выбрать случайное значение из массива, но сохранить его уникальным как можно дольше.

например, если я выбираю значение в 4 раза из массива из 4 элементов, выбранное значение должно быть случайным, но каждый раз разные.

Если я выбираю его 10 раз из того же массива из 4 элементов, то, очевидно, некоторые значения будут дублироваться.

У меня есть это прямо сейчас, но я все еще получаю повторяющиеся значения, даже если цикл выполняется 4 раз:

$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 ответов


вы почти правы. Проблема была в unset($arr_history[$selected]); линии. Значение $selected не является ключом, но на самом деле значением, поэтому unset не будет работать.

чтобы сохранить его таким же, как у вас там:

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

или пример с несколькими строками меньше:

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

как насчет перетасовки массива, и выталкивание детали.

, когда pop возвращает null обнулить массив.

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

конечно, вы захотите инкапсулировать это лучше, и сделать лучшую проверку, и другие такие вещи.


Php имеет собственную функцию shuffle который вы можете использовать для случайного порядка элементов в массиве. Так что насчет этого?

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

$random = shuffle($arr);

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

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

?>

ключ != значение, используйте это:

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

Я сделал это, чтобы создать случайные 8-значный пароль для пользователей:

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

Если вас не волнует, какие конкретные значения находятся в массиве, вы можете попытаться реализовать линейный конгруэнтный генератор для генерации всех значений в массиве.

реализация LCG

Википедия перечисляет некоторые значения, которые вы можете использовать, и правила выбора значений для алгоритма LCG, поскольку алгоритм LCG является детерминированным, гарантируется, что он не повторит ни одного значения до длины периода.

после заполнения массив с этими уникальными номерами, вы можете просто получить номера в массиве 1 на 1 в порядке.


легкий и чистый:

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