Reputation: 16142
I have the following array
$arr = array(
"person1" => 10,
"person2" => 10,
"person3" => 20,
"person4" => 25,
"person5" => 35,
);
I would like to write a function that takes $arr
as an argument and returns 3 elements of the array based on the values stored in each element.
For example if the returned subset yields
$newArr = array(
"person5" => 35,
"person1" => 10,
"person4" => 25,
);
There was a 35% chance that person5 would be the first element stored in $newArr
based on the value stored in $arr['person5']
divided by the sum of values stored in the remaining elements.
$arr['person5']/($arr['person5'] + $arr['person4'] + $arr['person3'] + $arr['person2'] + $arr['person1'])
There was a ~15% chance that person1 would be the second element stored in $newArr
based on the value stored in $arr['person1']
divided by the sum of values stored in the remaining elements.
$arr['person1']/($arr['person4'] + $arr['person3'] + $arr['person2'] + $arr['person1'])
There was a ~45% chance that person4 would be the second element stored in $newArr
based on the value stored in $arr['person4']
divided by the sum of values stored in the remaining elements.
$arr['person4']/($arr['person4'] + $arr['person3'] + $arr['person2'])
How could I write a function that does this?
Upvotes: 1
Views: 88
Reputation: 15130
You're looking for a roulette wheel selection algorithm, see: http://en.wikipedia.org/wiki/Fitness_proportionate_selection
$count = 3;
$arr = array(
"person1" => 10,
"person2" => 10,
"person3" => 20,
"person4" => 25,
"person5" => 35,
);
$result = array();
// sort from low to high
asort($arr);
// loop 3 times (based on count)
while ($count > 0){
// get the sum of all persons
$sum = 0;
foreach ($arr as $rank){
$sum += $rank;
}
// get a random value between 0 and sum
$delta = rand(0, $sum);
$current = 0;
// keep looping over each item, increasing rank untill $sum has surpassed delta
// see each item as as person containing a portion of the slice. The bigger the value, the greater the change of being selected
$current = 0;
foreach ($arr as $name => $rank){
$current += $rank;
if ($delta <= $current){
$result[$name] = $rank;
break;
}
}
unset($arr[$name]);
$count--;
}
Upvotes: 1