Search code examples
phparraysmultidimensional-arraysumgrouping

Group values from a 3d array into an associative 2d array and sum values with a shared path


I have already seen this stackoverflow page but it is not helping me.

I want to group by two columns and sum the values of a third column.

If the discount_id and dis_percent are the same then add the discount_value.

Here is my array:

$dis = [
    [['Dis_id' => 'Dl-Dis1'], ['Dis_per' => '7.500'], ['Dis_val' => '192.75']],
    [['Dis_id' => 'Dl-Dis2'], ['Dis_per' => '2.500'], ['Dis_val' => '97.88']],
    [['Dis_id' => 'Dl-Dis1'], ['Dis_per' => '5.000'], ['Dis_val' => '39.90']],
    [['Dis_id' => 'Dl-Dis2'], ['Dis_per' => '2.500'], ['Dis_val' => '99.90']]
];

The output that I need is:

D1-Dis1->7.5->192.75
D1-Dis1->5.0->39.9
D1-Dis2->2.5->197.78

My code looks like this:

$newarr = array();
$reverse_map = array();

foreach($dis as $idx => $entry) {
    if (isset($reverse_map[$entry['Dis_id']])) {
         // have we seen this name before? retrieve its original index value
         $idx = $reverse_map[$entry['Dis_id']]; 
    } else {
         // nope, new name, so store its index value
         $reverse_map[$entry['Dis_id']] = $idx;
    }

    // copy the 'constant' values
    $newarr[$idx]['Dis_id'] = $entry['Dis_id'];
    $newarr[$idx]['Dis_per'] = $entry['Dis_per'];

    // sum the qtd_post values to whatever we previously stored.        
    foreach($entry['Dis_val'] as $x => $y) {
        $newarr[$idx]['Dis_val'][$x] += $y;
    }
}

Solution

  • This is the solution I've come up with based off of the understanding that your intended array structure was as so;

    $dis = array(
        array(
            'Dis_id'  => 'Dl-Dis1',
            'Dis_per' => 7.500,
            'Dis_val' => 192.75
        ),
        ...
    );
    

    It determines the solution by creating a multidimensional array where the first dimension is the Dis_id, and the second dimension is the Dis_per, and the value becomes the sum of the Dis_val;

    $sums = array();
    
    foreach ($dis as $entry) {
        if (!isset($sums[$entry['Dis_id']])) {
            $sums[$entry['Dis_id']] = array();
        }
        if (!isset($sums[$entry['Dis_id']]["{$entry['Dis_per']}"])) {
            $sums[$entry['Dis_id']]["{$entry['Dis_per']}"] = 0;
        }
        $sums[$entry['Dis_id']]["{$entry['Dis_per']}"] += $entry['Dis_val'];
    }
    

    See this working example; https://eval.in/158661