- To target smaller limits first, call
asort() to order your elements ascending and preserve the original indexes.
- Then loop over the elements and update their value to be the lesser amount of their original value and the amount remaining in the total.
- Then reduce the total by the amount applied to the element and repeat.
- Before returning the updated elements, return them to their original order, if it matters.
This effectively fills the smaller capacities before larger capacities and never overfills. Demo
function splitItems(array $limits, int $total): array {
asort($limits);
foreach ($limits as &$limit) {
$limit = min($limit, $total);
$total -= $limit;
}
ksort($limits);
return $limits;
}
var_export(splitItems([14, 2], 10));
echo "\n---\n";
var_export(splitItems([6, 8, 2], 14));
echo "\n---\n";
var_export(splitItems([6, 4, 2], 14));
echo "\n---\n";
var_export(splitItems([7, 7, 1], 4));
echo "\n---\n";
var_export(splitItems([1, 1], 10));
echo "\n---\n";
var_export(splitItems([2,1,3],4));
Output:
array (
0 => 8,
1 => 2,
)
---
array (
0 => 6,
1 => 6,
2 => 2,
)
---
array (
0 => 6,
1 => 4,
2 => 2,
)
---
array (
0 => 3,
1 => 0,
2 => 1,
)
---
array (
0 => 1,
1 => 1,
)
---
array (
0 => 2,
1 => 1,
2 => 1,
)
p.s. If you don't care about filling the smallest capacity first, or if filling the items in order of their initial position is desired, just remove the two *sort() calls.
Update: For balanced distribution, you can loop over the containers one-at-a-time until they are full or the total is entirely consumed. Demo
function splitItems(array $limits, int $total): array {
$i = 0;
$count = count($limits);
$result = array_fill(0, $count, 0); // set 0 defaults for all containers
do {
if ($result[$i] < $limits[$i]) { // this container still has room
++$result[$i]; // add 1 to container
--$total; // subtract 1 from total
}
$i = ($i + 1) % $count; // update $i with circular access to allow restarting from 0
} while ($total && $result !== $limits); // loop until $total is emptied or all limits are filled
return $result;
}
the array keys are the max value for each group...it's unclear what this means in relation to the sample data supplied. In your example([14,2],10)the array keys of the supplied array will be0and1. But the values in your output groups are8and2. Did you mean to say the array values (i.e.14and2in that example)? Make sure you get the terminology right, otherwise the question can be come ambiguous or confusing.splitItems([1,1],10); the result is correct. But also, is the rule meant to be that the smallest capacities get satisfied first? Are the distributions generally meant to be balanced-ish? Is it intended that the largest capacity been given the fewest items when there are insufficient items? Do we have enough challenging test cases to fully interpret and test the requirements?