Search code examples
phparraysmultidimensional-arraysumgrouping

Group data in a 3d array by a column and sum the relative subarray data in two other columns


I am trying to group row data from a 3-dimensional array by a column value and sum subarray data in each respective group.

[
    [
        'name' => 'Edward Foo',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [10,      20,       50      ],
    ],
    [
        'name' => 'Michael Max',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [10,      10,       10      ],
    ],
    [
        'name' => 'Edward Foo',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [5,       10,       30      ],
    ],
    [
        'name' => 'Michael Max',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [8,       8,        20      ],
    ],
]

Desired output:

[
    [
        'name' => 'Edward Foo',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [15,      30,       80      ],
    ],
    [
        'name' => 'Michael Max',
        'desc_topic' => ['Apple', 'Banana', 'Orange'],
        'qtd_posts' =>  [18,      18,       30      ],
    ],
]

Solution

  • I'm assuming the following:

    1. every name entry in the original array has an identical desc_topic sub-array (e.g. they all have the same Apple/Banana/Orange values for every instance.
    2. the qtd_posts sub-array has the to-be-grouped values in the same corresponding slots (e.g. all '1' entries are to be summed together, all '2' entries summed together, etc...)
    3. You want to preserve the parent array keys so that all 'Edward Foo' entries will use the first key used by an Edward Foo entry (e.g. 0)

    If that applies, then something like this should work:

    $newarr = array();
    $reverse_map = array();
    
    foreach($array as $idx => $entry) {
        if (isset($reverse_map[$entry['name']]) {
             // have we seen this name before? retrieve its original index value
             $idx = $reverse_map[$entry['name']]; 
        } else {
             // nope, new name, so store its index value
             $reverse_map[$entry['name']] = $idx;
        }
    
        // copy the 'constant' values
        $newarr[$idx]['name'] = $entry['name'];
        $newarr[$idx]['desc_top'] = $entry['desc_topic'];
    
        // sum the qtd_post values to whatever we previously stored.        
        foreach($entry['qtd_posts'] as $x => $y) {
            $newarr[$idx]['qtd_posts'][$x] += $y;
        }
    }