Выбрать случайный индекс массива с условием на значение
У меня есть массив булевых значений, из которого я хочу выбрать случайный индекс, значение которого равно true, и установить его в false.
Я могу, конечно, сделать это с помощью грубой силы, выбирая индексы, пока не попаду в тот, значение которого истинно:
$arr = array(true, false, false, true, false, true);
var_dump($arr);
$i = array_rand($arr);
while(!$arr[$i])
{
$i = array_rand($arr);
}
$arr[$i] = false;
var_dump($arr);
Это создает что-то вроде этого, где четвертая запись была изменена.
array(6) {
[0]=>
bool(true)
[1]=>
bool(false)
[2]=>
bool(false)
[3]=>
bool(true)
[4]=>
bool(false)
[5]=>
bool(true)
}
array(6) {
[0]=>
bool(true)
[1]=>
bool(false)
[2]=>
bool(false)
[3]=>
bool(false)
[4]=>
bool(false)
[5]=>
bool(true)
}
Однако мне приходится проделывать эту операцию несколько раз со значительно большим массивом. В какой-то момент массив почти полностью ложен, и в этом случае зверь силовой метод довольно неэффективен.
Есть ли более изящный метод решения этой проблемы? Любой вид array_rand()
функции, где я могу дать предварительное условие?3 ответа:
$arr = array(true,true,false,false,true,false); $res = array_keys($arr, true); var_dump($res); // returns 0,1,4 echo $res[array_rand($res)]; //echo one of the indexes that is true
Приведенный выше код возвращает индексы истинных значений $arr в $res.
Правка. Чтобы затем установить один из индексов $arr как false, вы должны:
$arr[$res[array_rand($res)]] = false; // will set one as false.
Зацикливание этих двух строк в конечном итоге установит все индексы в false:
$res = array_keys($arr, true); $arr[$res[array_rand($res)]] = false;
Вы можете использовать следующий код:
$arr = array(true, false, false, true, false, true); $randTrueIndex = array_rand(array_filter($arr, function($item) { return $item; })); $arr[$randTrueIndex] = false;
Самым простым способом сделать это, не тратя впустую никаких усилий, было бы создать случайную перестановку индексов массива. Перемешивание кнута (также известное какFisher-Yates shuffle ) должно работать превосходно.
Другим вариантом для некоторых приложений будет выбор генератора, который создает значения в желаемом диапазоне без повторения или только с относительно небольшим числом выбросов (значения, которые выходят за пределы целевого диапазона). Например, все линейно-конгруэнтные генераторы обладают тем свойством, что любые младшие N битов имеют цикл с периодом 2^n. выберите первую степень из двух, которая не меньше размера вашего массива, и вы будете генерировать меньше одного потерянного числа для каждого хорошего в среднем.