'group/sum multiple related arrays
4 arrays given. I want to group the arrays by it's value if they have the same value on different positions and sum the integer value if grouped.
$arr1 = ["101","206", "206"];
$arr2 = ["PA701", "PA700", "PA700"];
$arr3 = ["2022-04-01", "2022-04-07", "2022-04-07"];
$arr4 = [70, 1040, 1625];
//expected Result
$res1 = ["101","206"];
$res2 = ["PA701", "PA700"];
$res3 = ["2022-04-01", "2022-04-07"];
$res4 = [70, 2665];
array 1-3 are linked together so the grouping is only allowed if the value of each array of them is the same on multiple positions.
This example is not grouped because in $arr2 we have no related duplicates.
$arr1 = ["101","206", "206"];
$arr2 = ["PA701", "PA701", "PA700"];
$arr3 = ["2022-04-01", "2022-04-07", "2022-04-07"];
$arr4 = [70, 1040, 1625];
//expected Result
$res1 = ["101","206", "206"];
$res2 = ["PA701", "PA701", "PA700"];
$res3 = ["2022-04-01", "2022-04-07", "2022-04-07"];
$res4 = [70, 1040, 1625];
My attemt is working but only if the duplicate happens on the next position of the array, I want to make it work, regardles of the array position.
foreach($arr1 as $k=>$val)
{
if(isset($arr1[$k+1]))
{
if($arr1[$k] == $arr1[$k+1] && $arr2[$k] == $arr2[$k+1] && $arr3[$k] == $arr3[$k+1])
{
unset($arr1[$k+1]);
unset($arr2[$k+1]);
unset($arr3[$k+1]);
$arr4[$k] += $arr4[$k+1];
unset($arr4[$k+1]);
}
}
}
Example here
Solution 1:[1]
This is probably easiest with an array_map and an array_reduce. First you aggregate all those separate arrays into one with specific entries for each index. Then you reason for each entry in that array if we should add it to the grouped array, or if we already have a duplicate item.
We obviously don't have any safeguarding built in. For example, we don't check if the arrays are of the same length, or if the items in $arr4
are all numeric, or if the entries in the other arrays can be easily compared with a ===
.
$arr1 = ["101","206", "206"];
$arr2 = ["PA701", "PA700", "PA700"];
$arr3 = ["2022-04-01", "2022-04-07", "2022-04-07"];
$arr4 = [70, 1040, 1625];
$items = array_map(
function ($item1, $item2, $item3, $item4) {
return [
'item1' => $item1,
'item2' => $item2,
'item3' => $item3,
'item4' => $item4
];
},
$arr1,
$arr2,
$arr3,
$arr4
);
// group by item1/2/3
$groupedItems = array_reduce(
$items,
function ($acc, $entry) {
// First we figure out if there is a duplicate in our current reduced array
$duplicateEntryIndex = null;
foreach ($acc as $accIndex => $accEntry) {
if ($accEntry['item1'] === $entry['item1'] && $accEntry['item2'] === $entry['item2'] && $accEntry['item3'] === $entry['item3']) {
$duplicateEntryIndex = $accIndex;
break;
}
}
if (is_null($duplicateEntryIndex)) {
// If we do not have a duplicate entry, we just add the current entry to the new grouped array
$acc[] = $entry;
} else {
// Otherwise we modify the existing entry to be the sum of the two
$acc[$duplicateEntryIndex]['item4'] += $entry['item4'];
}
return $acc;
},
[]
);
var_dump($groupedItems);
Solution 2:[2]
This task could be achieved with more elegance if you weren't working with 4 individual variables. A multidimensional array containing 4 subarrays would make things easier to program.
Anyhow, don't do more than one loop. You just need to assign temporary composite keys based on the 3 identifying column values, then sum the 4th when a match group is encountered more than once. Remove the temporary keys after the loop is finished with array_values()
, if you like.
Code: (Demo)
$arr1 = ["101","206", "206"];
$arr2 = ["PA701", "PA700", "PA700"];
$arr3 = ["2022-04-01", "2022-04-07", "2022-04-07"];
$arr4 = [70, 1040, 1625];
foreach ($arr1 as $i => $value) {
$compositeKey = "{$value}_{$arr2[$i]}_{$arr3[$i]}";
if (!isset($res1[$compositeKey])) {
$res1[$compositeKey] = $value;
$res2[$compositeKey] = $arr2[$i];
$res3[$compositeKey] = $arr3[$i];
$res4[$compositeKey] = $arr4[$i];
} else {
$res4[$compositeKey] += $arr4[$i];
}
}
var_export(array_values($res1));
var_export(array_values($res2));
var_export(array_values($res3));
var_export(array_values($res4));
Output:
array (
0 => '101',
1 => '206',
)array (
0 => 'PA701',
1 => 'PA700',
)array (
0 => '2022-04-01',
1 => '2022-04-07',
)array (
0 => 70,
1 => 2665,
)
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 | Sumurai8 |
Solution 2 | mickmackusa |