phplaravelsumgroupinglaravel-collection

Group 2d Laravel collection by two columns and sum a third column within each group


I have this collection:

$stocks = collect(
    [
        ['sku' => '123', 'batch' => '123', 'qty_total' => 1],
        ['sku' => '1233', 'batch' => '123', 'qty_total' => 2],
        ['sku' => '123', 'batch' => '123', 'qty_total' => 3],
        ['sku' => '5', 'batch' => '123', 'qty_total' => 4],
    ]
);

And I need get in output collection like this:

[
        ['sku' => '123', 'batch' => '123', 'qty_total' => 4],
        ['sku' => '1233', 'batch' => '123', 'qty_total' => 2],
        ['sku' => '5', 'batch' => '123', 'qty_total' => 4],
    ]

I'm grouping collection with

$coll = $coll
    ->groupBy(['sku','batch'], true)

But I don't understand how I must sum next.


Solution

  • Feeding a 2-element array to the groupBy() method only makes more work/handling because it generates an unnecessarily deep structure. Notice how Mohammad's snippet has to reindex (values()), then call first(), then first() again just to traverse to the desired level.

    Instead, feed groupBy() a callback function to form a "composite string key" and keep the grouped data shallow.

    Code: (PHPize Demo)

    var_export(
        $stocks
        ->groupBy(fn($row) => $row['sku'] . '_' . $row['batch'])
        ->map(fn($set) => array_merge($set->first(), ['qty_total' => $set->sum('qty_total')]))
        ->values()
        ->toArray()
    );
    

    Output:

    array (
      0 => 
      array (
        'sku' => '123',
        'batch' => '123',
        'qty_total' => 4,
      ),
      1 => 
      array (
        'sku' => '1233',
        'batch' => '123',
        'qty_total' => 2,
      ),
      2 => 
      array (
        'sku' => '5',
        'batch' => '123',
        'qty_total' => 4,
      ),
    )
    

    Topically related content: