получите случайное значение из массива 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;
}
<?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 является детерминированным, гарантируется, что он не повторит ни одного значения до длины периода.
после заполнения массив с этими уникальными номерами, вы можете просто получить номера в массиве 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);
