I'm trying to group the data in an array of associative arrays by three columns (year
, month
, grupo
) and sum another column (quantity
).
Given an array like:
$in = [
['year' => '2010', 'month' => '11', 'grupo' => '2', 'quantity' => 3],
['year' => '2010', 'month' => '11', 'grupo' => '3', 'quantity' => 4],
['year' => '2011', 'month' => '2', 'grupo' => '2', 'quantity' => 4],
['year' => '2011', 'month' => '2', 'grupo' => '2', 'quantity' => 4],
['year' => '2012', 'month' => '3', 'grupo' => '4', 'quantity' => 3]
['year' => '2012', 'month' => '3', 'grupo' => '4', 'quantity' => 3]
];
I want get:
[
['year' => '2010', 'month' => '11', 'grupo' => '2', 'quantity' => 3],
['year' => '2010', 'month' => '11', 'grupo' => '3', 'quantity' => 4],
['year' => '2011', 'month' => '2', 'grupo' => '2', 'quantity' => 8],
['year' => '2012', 'month' => '3', 'grupo' => '4', 'quantity' => 6]
]
I've tried something like this:
$out = array();
foreach ($in as $row) {
if (!isset($out[$row['year']['month']['grupo']])) {
$out[$row['year']['month']['grupo']] = array(
'year' => $row['year'],
'month' => $row['month'],
'grupo' => $row['grupo'],
'quantity' => 0,
);
}
$out[$row['year']['month']['grupo']]['quantity'] += $row['quantity'];
}
$out = array_values($out);
but it fails while trying to group the 3 fields.
I think the earlier answers overlooked the desired result -- the solutions from @hellcode and @Rasclatt create unnecessarily deep structures.
The coding attempt in the question was very close to being right, there was only a flaw in generating unique grouping keys in the first level.
To generate unique grouping keys, you must forge a string from the multiple identifying values in the row. In other words, "compose" a unique value from the three targeted column values -- a composite key.
Code: (Demo)
$result = [];
foreach ($in as $row) {
$compositeKey = implode(array_slice($row, 0, 3));
if (!isset($result[$compositeKey])) {
$result[$compositeKey] = $row;
} else {
$result[$compositeKey]['quantity'] += $row['quantity'];
}
}
var_export(
array_values($result)
);