I have an array to be summed by column(s)
Array (
0 => [
[category] => Tools, furniture & fixtures
[period] => 2022-07
[depreciation] => 100
],
1 => [
[category] => Tools, furniture & fixtures
[period] => 2022-07
[depreciation] => 50
],
2 => [
[category] => Machines
[period] => 2022-07
[depreciation] => 25
],
3 => [
[category] => Machines
[period] => 2022-07
[depreciation] => 75
],
4 => [
[category] => Machines
[period] => 2022-08
[depreciation] => 200
]
)
I want to sum depreciation column by combination of category and period column, something like :
Array (
0 => [
[category] => Tools, furniture & fixtures
[period] => 2022-07
[depreciation] => 150
],
1 => [
[category] => Machines
[period] => 2022-07
[depreciation] => 100
],
2 => [
[category] => Machines
[period] => 2022-08
[depreciation] => 200
]
)
I tried to used to utilize this function to do this IF only one column as the parameter/key, and no idea if it have to be more than one column (category and period) :
$itemsSummed = [];
foreach ($depreciations as $item) {
if (array_key_exists($item['category'], $itemsSummed)) {
$itemsSummed[$item['category']]['depreciation'] = $item['depreciation'];
} else {
$itemsSummed[$item['category']] = $item;
}
}
$itemsSummed = array_values($itemsSummed);
How can i achieve this ?
CodePudding user response:
The easiest way to do that is pooling the sums together based on unique keys, which in your case are concatenated from "category" and "period". First things first, your data:
$data = [
0 => [
'category' => 'Tools, furniture & fixtures',
'period' => '2022-07',
'depreciation' => '100'
],
1 => [
'category' => 'Tools, furniture & fixtures',
'period' => '2022-07',
'depreciation' => 50
],
2 => [
'category' => 'Machines',
'period' => '2022-07',
'depreciation' => 25
],
3 => [
'category' => 'Machines',
'period' => '2022-07',
'depreciation' => 75
],
4 => [
'category' => 'Machines',
'period' => '2022-08',
'depreciation' => '200'
]
];
Then let's iterate your data:
$sums = [];
foreach($data as $vals) {
// Concatenate category period for unique grouping key:
$sum_key = "{$vals['category']}__{$vals['period']}";
// Set sum to zero if not defined yet:
$sums[$sum_key] ??= 0;
// Add depreciation
$sums[$sum_key] = $vals['depreciation'];
}
This would give you the following:
array(3) {
["Tools, furniture & fixtures__2022-07"] · int(150)
["Machines__2022-07"] · int(100)
["Machines__2022-08"] · int(200)
}
That's the basic logic. To model the output in the form of your source array, we'll follow the logic above with the difference that in place of ??= 0
, we initialize the "sum" item with the values common to each group, and then add to the "depreciation" value at each iteration:
foreach($data as $vals) {
// Concatenate category period for unique grouping key:
$sum_key = "{$vals['category']}__{$vals['period']}";
// Initialize the grouped array item with zero "summable":
$sums[$sum_key] ??= [
'category' => $vals['category'],
'period' => $vals['period'],
'depreciation' => 0,
];
// Add depreciation:
$sums[$sum_key]['depreciation'] = $vals['depreciation'];
}
This would give you:
array(3) {
["Tools, furniture & fixtures__2022-07"] · array(3) {
["category"] · string(27) "Tools, furniture & fixtures"
["period"] · string(7) "2022-07"
["depreciation"] · int(150)
}
["Machines__2022-07"] · array(3) {
["category"] · string(8) "Machines"
["period"] · string(7) "2022-07"
["depreciation"] · int(100)
}
["Machines__2022-08"] · array(3) {
["category"] · string(8) "Machines"
["period"] · string(7) "2022-08"
["depreciation"] · int(200)
}
}
If the grouping keys look awkward, or if you just want a numerically indexed array per your sample outcome, array_values($sums)
in the end will "clean it up". I've left it as is to highlight the logic of using a "unique grouping key" to aggregate values.
CodePudding user response:
$list = [
[ 'category' => 'Tools', 'period' => '2022 - 07', 'depreciation' => 100 ],
[ 'category' => 'Tools', 'period' => '2022 - 07', 'depreciation' => 50 ],
[ 'category' => 'Machines', 'period' => '2022 - 07', 'depreciation' => 25 ],
[ 'category' => 'Machines', 'period' => '2022 - 07', 'depreciation' => 75 ],
[ 'category' => 'Machines', 'period' => '2022 - 08', 'depreciation' => 200 ]
];
$result = array_reduce(
$list,
function ($carry, $item) {
if (is_array($carry)) {
foreach ($carry as &$value) {
if ($value['category'] === $item['category'] && $value['period'] === $item['period']) {
$value['depreciation'] = $item['depreciation'];
return $carry;
}
}
return [ ...$carry, $item ];
}
return $item;
},
[]
);
print_r($result);