How to group by and sum a multi-dimensional array?

2019-06-14 16:44发布

问题:

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;
    }
}

回答1:

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



回答2:

As you iterate your input array, you will need to isolate the Dis_id and Dis_per values and use them as keys when storing your Dis_val.

If there no value present for a [Dis_id][Dis_per] element, then you can simply store the value. If there is a pre-existing value, you need to add the new value to the stored value. isset() is most efficient function to aid in the identification of new/existing elements in the result array.

Code: (Demo)

$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']]
];

foreach ($dis as $group) {
    $id = $group[0]['Dis_id'];
    $per = $group[1]['Dis_per'];
    if (!isset($result[$id][$per])) {
        $result[$id][$per] = $group[2]['Dis_val'];
    } else {
        $result[$id][$per] += $group[2]['Dis_val'];
    }
}
var_export($result);

Output:

array (
  'Dl-Dis1' => 
  array (
    '7.500' => '192.75',
    '5.000' => '39.90',
  ),
  'Dl-Dis2' => 
  array (
    '2.500' => 197.78,
  ),
)