choices() Laravel helper

The choices() helper method returns multiple random elements from the list with replacement. This provides easy way to more controlled randomness whether it is seeds or other cases.

The list should contain a randomly selection of the values from a specified list, and there should be 10 times higher possibility to select "apple" than the other two.

Example:

choices(['apple', 'banana', 'cherry'], [10, 1, 1]);
choices(['apple', 'banana', 'cherry'], [10, 1, 1]);

Source:

if (! function_exists('choices')) {
/**
* @param array<mixed> $population
* @param array<int> $weights
*/
function choices(array $population, array $weights): mixed
{
if (empty($population)) {
throw new \Exception('Population is empty');
}
 
if (count($population) !== count($weights)) {
throw new \Exception('Population and weights length do not match');
}
 
if (! collect($weights)->every(fn ($i) => is_int($i))) {
throw new \Exception('All weights must be integers');
}
 
$pick = null;
$zip = collect($population)->zip($weights)->toArray();
 
$totalWeights = array_sum(array_column($zip, 1));
 
$random = mt_rand(0, $totalWeights - 1);
 
foreach ($zip as $x) {
if ($random < $x[1]) {
$pick = $x[0];
break;
}
 
$random -= $x[1];
}
 
return $pick;
}
}
if (! function_exists('choices')) {
/**
* @param array<mixed> $population
* @param array<int> $weights
*/
function choices(array $population, array $weights): mixed
{
if (empty($population)) {
throw new \Exception('Population is empty');
}
 
if (count($population) !== count($weights)) {
throw new \Exception('Population and weights length do not match');
}
 
if (! collect($weights)->every(fn ($i) => is_int($i))) {
throw new \Exception('All weights must be integers');
}
 
$pick = null;
$zip = collect($population)->zip($weights)->toArray();
 
$totalWeights = array_sum(array_column($zip, 1));
 
$random = mt_rand(0, $totalWeights - 1);
 
foreach ($zip as $x) {
if ($random < $x[1]) {
$pick = $x[0];
break;
}
 
$random -= $x[1];
}
 
return $pick;
}
}