Reputation: 805
I have an array of booleans, from which I want to pick a random index whose value is true and set it to false.
I can, of course, do this with brute force by picking indices until I hit one whose value is true:
$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);
This creates something like this, where the fourth entry got changed.
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)
}
However, I have to do this operation several times with a significantly larger array. At some point the array is nearly completely false, in which case the brute force method is rather inefficient.
Is there any more elegant method of solving this problem? Any kind of array_rand()
function, where I can give a precondition?
Upvotes: 3
Views: 1303
Reputation: 23958
$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
The above code returns the indexes of the true values of $arr in $res.
Edit. To then set one of $arr indexes as false you should:
$arr[$res[array_rand($res)]] = false; // will set one as false.
Looping these two lines will eventually set all indexes to false:
$res = array_keys($arr, true);
$arr[$res[array_rand($res)]] = false;
Upvotes: 2
Reputation: 4665
The simplest way to do this without wasting any work would be to create a random permutation of the array indices. The Knuth shuffle (also known as Fisher-Yates shuffle) should work admirably.
Another option for certain applications would be picking a generator that creates values in the desired range without repetition, or with only a comparatively small number of outliers (values that fall outside the target range). For example, all linear-congruential generators have the property that any lower n bits cycle with period 2^n. Pick the first power of two that is not less than your array size and you'll generate less than one wasted number for every good one on average.
Upvotes: 0
Reputation: 10450
You can use the following code:
$arr = array(true, false, false, true, false, true);
$randTrueIndex = array_rand(array_filter($arr, function($item) {
return $item;
}));
$arr[$randTrueIndex] = false;
Upvotes: 1