phparraysmultidimensional-arraysumgrouping

Group rows of a 2d array by a column and sum another column within each group


How to group array by 'tax'and 'concept' and SUM attribute 'val'?

I looking for create a single object when tax and concept are the same, also SUM the val.

I tried with simple foreach and validation inside, but doesnt work.

echo json_encode($array);

Array Print

[
 {
    "tax": "10",
    "concept": "TUC",
    "val": "10"
 },
 {
    "tax": "10",
    "concept": "TUC",
    "val": "86"
 },
 {
    "tax": "15",
    "concept": "TUC",
    "val": "8"
 },
 {
    "tax": "11",
    "concept": "IPS",
    "val": "6"
 },
 {
    "tax": "11",
    "concept": "IPS",
    "val": "45"
 }  
]

Expected Result

[
 {
    "tax": "10",
    "concept": "TUC",
    "val": "96"
 },
 {
    "tax": "15",
    "concept": "TUC",
    "val": "8"
 },
 {
    "tax": "11",
    "concept": "IPS",
    "val": "51"
 }
]

Solution

  • You can use array_reduce() here. You'll use the tax value as a key you're grouping on, and reduce the array to unique tax elements while simultaneously producing the sum of val values. The only caveat with this approach is that transforming it to JSON will make PHP think that the outer element is an object and not an array (even though it is an array, this is because we end up using non-default array indexing). But, this is easily mitigated with a call to array_values().

    $array = // your array from above
    $result = array_reduce($array, function($carry, $item) { 
        if(!isset($carry[$item->tax])) {
            $carry[$item->tax] = $item;
        } else {
            $carry[$item->tax]->val += $item->val;
        }
        return $carry;
    });
    
    $result = array_values($result);
    
    echo json_encode($result);
    

    You can see from this demo that it produces:

    [{
        "tax": "10",
        "concept": "TUC",
        "val": 96
    }, {
        "tax": "15",
        "concept": "TUC",
        "val": "8"
    }, {
        "tax": "11",
        "concept": "IPS",
        "val": 51
    }]