'Group rows by column and sum another column within groups [duplicate]
I have an array looking like:
array(480) {
[0]=>
array(2) {
["tag_id"]=>
string(4) "6291"
["az"]=>
int(5)
}
[1]=>
array(2) {
["tag_id"]=>
string(4) "6291"
["az"]=>
int(4)
}
[2]=>
array(2) {
["tag_id"]=>
string(4) "6311"
["az"]=>
int(4)
}
[3]=>
array(2) {
["tag_id"]=>
string(4) "6427"
["az"]=>
int(4)
}
How can I reduce the array, so that "az" sums all values of "az", if "Tag_ID" is identical? Expected Output:
array(479) {
[0]=>
array(2) {
["tag_id"]=>
string(4) "6291"
["az"]=>
int(9)
}
[1]=>
array(2) {
["tag_id"]=>
string(4) "6311"
["az"]=>
int(4)
}
[2]=>
array(2) {
["tag_id"]=>
string(4) "6427"
["az"]=>
int(4)
}
I tried with array_reduce but can not figure the function to use in it. Thanks a lot!
Solution 1:[1]
You'll have to use array_walk()
to modify the array. array_reduce()
is to calculate a single value and not to change the array itself.
I would do something like this:
<?php
$array = [
[
'tag_id' => "6291",
'az' => 5,
],
[
'tag_id' => "6291",
'az' => 4,
],
[
'tag_id' => "6311",
'az' => 4,
],
[
'tag_id' => "6427",
'az' => 4,
]
];
$tag_id_indexes = []; // To store the index of the first tag_id found.
array_walk(
$array,
function ($sub_array, $index) use (&$array, &$tag_id_indexes) {
// Store the index of the first tag_id found.
if (!isset($tag_id_indexes[$sub_array['tag_id']])) {
$tag_id_indexes[$sub_array['tag_id']] = $index;
}
else { // This tag_id already exists so we'll combine it.
// Get the index of the previous tag_id.
$first_tag_id_index = $tag_id_indexes[$sub_array['tag_id']];
// Sum the az value.
$array[$first_tag_id_index]['az'] += $sub_array['az'];
// Remove this entry.
unset($array[$index]);
}
}
);
print "The reduced array but with the original indexes:\n" . var_export($array, true) . "\n";
// If you want new indexes.
$array = array_values($array);
print "The reduced array with new indexes:\n" . var_export($array, true) . "\n";
You can test it here: https://onlinephp.io/c/58a11
This is the output:
The reduced array but with the original indexes:
array (
0 =>
array (
'tag_id' => '6291',
'az' => 9,
),
2 =>
array (
'tag_id' => '6311',
'az' => 4,
),
3 =>
array (
'tag_id' => '6427',
'az' => 4,
),
)
The reduced array with new indexes:
array (
0 =>
array (
'tag_id' => '6291',
'az' => 9,
),
1 =>
array (
'tag_id' => '6311',
'az' => 4,
),
2 =>
array (
'tag_id' => '6427',
'az' => 4,
),
)
Solution 2:[2]
You can use array_reduce in natural way:
$res = array_reduce(
$array,
function($ac, $el) {
$ac[$el['tag_id']] += $el['az'];
return $ac;
},
[]
);
print_r($res);
It will build array with tag_id
as key and az
as value:
Warning: Undefined array key 6291
Warning: Undefined array key 6311
Warning: Undefined array key 6427
Array
(
[6291] => 9
[6311] => 4
[6427] => 4
)
When you need to restore source array structure use array_map
$res = array_map(
fn($k, $v) => ['tag_id' => $k, 'az' => $v],
array_keys($res),
$res
);
Solution 3:[3]
I've created a bit of sample code that in theory does what you need it to do as long as you know what tag_id
may be, it uses array filter and checks if tag_id
equals what you've inputed:
$arr = array(
array("tag_id" => "6291", "az" => "int(5)"),
array("tag_id" => "6291", "az" => "int(4)"),
array("tag_id" => "6311", "az" => "int(4)"),
);
$results = array_filter($arr, function ($item) {
if ($item["tag_id"] == "6291") {
return true;
}
return false;
});
foreach ($results as $result) {
echo "tag_id = " . $result["tag_id"];
echo "az = " . $result["az"] . PHP_EOL;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Patrick Janser |
Solution 2 | mickmackusa |
Solution 3 | geertjanknapen |