Search code examples
phparraysmultidimensional-arraysumgrouping

Group (pivot) a 2d array by one column and sum values by another column in respective groups


I have a multidimensional array that has a date, name, & markup.

$in = [
    [
        'saledate' => '2016-02-01',
        'name' => 'John Doe',
        'markup' => 561
    ],
    [
        'saledate' => '2016-02-01',
        'name' => 'John Doe',
        'markup' => 681
    ],
    [
        'saledate' => '2016-02-02',
        'name' => 'John Doe',
        'markup' => 379
    ],
    [
        'saledate' => '2016-02-01',
        'name' => 'Jane Doe',
        'markup' => 205
    ],
    [
        'saledate' => '2016-02-02',
        'name' => 'Jane Doe',
        'markup' => 900
    ],
    [
        'saledate' => '2016-02-02',
        'name' => 'Jane Doe',
        'markup' => 787
    ],
    [
        'saledate' => '2016-02-03',
        'name' => 'Jane Doe',
        'markup' => 211
    ]
]

I'm trying to sum the values for each person by date for the desired output:

 0 => 
array (size=3)
  'name' => string 'John Doe' (length=8)
  '2016-02-01' => float 1242
  '2016-02-02' => float 379
 1 => 
array (size=3)
  'name' => string 'Jane Doe' (length=8)
   '2016-02-01' => float 205
   '2016-02-02' => float 1687
   '2016-02-03' => float 211

Here is what I have but I think I'm just confusing myself...

 $out = array();
 foreach ($in as $row)
 {
   $result[$row['saledate']]['saledate'] = $row['saledate'];
   $result[$row['name']]['name'] = $row['name'];
   $result[$row['date']]['markup'] += $row['markup'];
 }
 $out = array_values($out);

Solution

  • Store the name as the key in your output array, it'll make grouping the results easier:

    $out = array();
    foreach ($in as $row) {
    
      /* set the key using the name, eg. $out['John Doe'] */
      if (! isset($out[$row['name']])) {
        $out[$row['name']] = array('name' => $row['name']); 
      }
    
      /* if the saledate isn't already exist, set it */
      if (! isset($out[$row['name']][$row['saledate']])) {
        $out[$row['name']][$row['saledate']] = 0;    
      }
    
      /* add the markup */
      $out[$row['name']][$row['saledate']] += $row['markup'];
    
    }
    

    Which would give you:

    Array
    (
        [John Doe] => Array
            (
                [name] => John Doe
                [2016-02-01] => 1242
                [2016-02-02] => 379
            )
    
        [Jane Doe] => Array
            (
                [name] => Jane Doe
                [2016-02-01] => 205
                [2016-02-02] => 1687
                [2016-02-03] => 211
            )
    
    )
    

    If you don't want the name key, just use $out = array_values($out).