Reputation: 555
I need to split my associative array into bunches of not greater than 50 in each bunch. Multiple elements may be pushed into a given group to ensure that a group reaches 50 before starting a new group.
Sample input:
$array = [
'5' => 142,
'2' => 57,
'18' => 37
];
Desired result:
[
['5' => 50],
['5' => 50],
['5' => 42, '2' => 8],
['2' => 49, '18' => 1],
['18' => 36],
];
Upvotes: 1
Views: 190
Reputation: 19764
To create an array where the sum of each entry would not exceed a given amount, you can use an iterative approach.
Let's start with an empty array and a variable representing the working index of that array. As we go through the input array, we add the maximum possible remaining quantity to the new array. If we reach the limit, we increment the index variable. And we continue as long as the input array has not been completely browsed.
Code:
const MAX_SUM = 50;
$total = []; // Store the new data
$curKey = 0; // Store the current key of $total array.
foreach ($array as $key => $value) {
while ($value) {
// Get the current sum for the current key:
$curSum = array_sum($total[$curKey] ?? []);
// If the max was reached, we can go to the next key:
if ($curSum == MAX_SUM) $curKey++;
// Now, compute if the value to add (max to reach 50);
$add = $value + $curSum > MAX_SUM // If above,
? MAX_SUM - $curSum // got only the difference,
: $value; // else, use the full value.
// Add the value
$total[$curKey][$key] = $add;
// Finally, remove what we added just before.
$value -= $add;
}
}
print_r($total);
Outputs :
Array (
[0] => Array (
[5] => 50
)
[1] => Array (
[5] => 50
)
[2] => Array (
[5] => 42
[2] => 8
)
[3] => Array (
[2] => 49
[18] => 1
)
[4] => Array (
[18] => 36
)
)
See also a the nice answer of @mickmackusa.
Upvotes: 2
Reputation: 48001
My train of thought for this task aligns with @Syscall's "push & consume" approach.
Code: (Demo)
$groupLimit = 50; // declare as a variable to avoid "magic numbers" in code
$result = [];
$groupKey = 0;
foreach ($array as $key => $value) {
while ($value) {
$sum = array_sum($result[$groupKey] ?? []); // get group sum
$value -= $result[$groupKey][$key] = min($groupLimit - $sum, $value); // push key with limited value; decrease value
$groupKey += ($sum + $result[$groupKey][$key] === $groupLimit); // only increment group key if at $groupLimit
}
}
var_export($result);
Upvotes: 1