Home > OS >  How to sum all array keys according to a specific key value in multidimensional arrays i.e order id
How to sum all array keys according to a specific key value in multidimensional arrays i.e order id

Time:06-21

This is my sample data array;

Array
(
    [0] => Array
        (
            [id] => 2
            [order_id] => 1
            [adm_aftr_disc] => 25.5
            [sup_aftr_disc] => 186.99
            [discount] => 53.12
            [prod_disc] => 2
        )

    [1] => Array
        (
            [id] => 4
            [order_id] => 2
            [adm_aftr_disc] => 49.92
            [sup_aftr_disc] => 366.08
            [discount] => 104
            [prod_disc] => 2
        )

    [2] => Array
        (
            [id] => 1
            [order_id] => 1
            [adm_aftr_disc] => 4.02
            [sup_aftr_disc] => 76.43
            [discount] => 8.94
            [prod_disc] => 2
        )

    [3] => Array
        (
            [id] => 3
            [order_id] => 2
            [adm_aftr_disc] => 7.88
            [sup_aftr_disc] => 149.63
            [discount] => 17.49
            [prod_disc] => 2
        )

)

The result I want should be something like this;

Array
(
    [0] => Array
        (
            [id] => 3
            [order_id] => 1
            [adm_aftr_disc] => 29.52
            [sup_aftr_disc] => 263.42
            [discount] => 62.06
            [prod_disc] => 4
        )

    [1] => Array
        (
            [id] => 7
            [order_id] => 2
            [adm_aftr_disc] => 57.8
            [sup_aftr_disc] => 515.71
            [discount] => 121.49
            [prod_disc] => 4
        )
)

My sample code is

$result = array_reduce($update_prod_order, function($carry, $item) {
    foreach($item as $k => $v)
        $carry[$k] = $v   ($carry[$k] ?? 0);

    return $carry;
}, []);

Guidelines

  • The keys will be the same throughout all the array indexes.
  • The result script can be a function that takes a key. For example, if I give the order_id to the function then it will sum according to the order_id wise in such a way that the array indexes having the same order_id must be the sum, and the order_id should unique.

Your help means a lot to me. You can further ask anything you want. Thanks.

CodePudding user response:

At a very high level, it is usually easiest to create a new array with primary keys that map to the sub-key that you are grouping things by. Also, when doing this with order_id, it doesn't make sense to key id around unless you also define the logic for it such as "first found" or "last found", or you can create an array of found items. I'm just throwing it away but either should be fine.

$data = [
    [
            'id' => 2,
            'order_id' => 1,
            'adm_aftr_disc' => 25.5,
    ],
    [
            'id' => 4,
            'order_id' => 2,
            'adm_aftr_disc' => 10,
    ],
    [
            'id' => 6,
            'order_id' => 1,
            'adm_aftr_disc' => 50,
    ],
];

print_r(groupData($data));

function groupData(array $data) {
    
    // Our return array
    $ret = [];
    
    foreach($data as $item) {
        
        // This is what we're grouping on
        $orderId = $item['order_id'];
        
        // If it doesn't exist in the return array, add it with sane defaults
        if(!array_key_exists($orderId, $ret)){
            $ret[$orderId] = [
                'order_id' => $orderId,
                'adm_aftr_disc' => 0,
            ];
        }
        
        // Sum. Add more as needed
        $ret[$orderId]['adm_aftr_disc']  = $item['adm_aftr_disc'];
    }
    
    return $ret;
}

I didn't map your data exactly, and I didn't sum every possible sub-array, but I figured you could fill in the blanks on that.

I also didn't make a magic one-function-fits-all that supports passing a string to determine what to group on. If you want that, you need to define a list of supported keys and a list of columns that are summable. Or just write two functions.

Demo here: https://3v4l.org/0gnEj#v8.1.7

CodePudding user response:

This is a solution with array_reduce as you intended to do it. It'll return alls sums in one go:

$list = [
    [
        'id'            => 2,
        'order_id'      => 1,
        'adm_aftr_disc' => 25.5,
        'sup_aftr_disc' => 186.99,
        'discount'      => 53.12,
        'prod_disc'     => 2
    ],
    [
        'id'            => 4,
        'order_id'      => 2,
        'adm_aftr_disc' => 49.92,
        'sup_aftr_disc' => 366.08,
        'discount'      => 104,
        'prod_disc'     => 2
    ],
    [
        'id'            => 1,
        'order_id'      => 1,
        'adm_aftr_disc' => 4.02,
        'sup_aftr_disc' => 76.43,
        'discount'      => 8.94,
        'prod_disc'     => 2
    ],
    [
        'id'            => 3,
        'order_id'      => 2,
        'adm_aftr_disc' => 7.88,
        'sup_aftr_disc' => 149.63,
        'discount'      => 17.49,
        'prod_disc'     => 2
    ]
];

$result = array_reduce(
    $list,
    function ($carry, $item) {
      $orderId = $item['order_id'];
      if (array_key_exists($orderId, $carry)) {
        $preItem = $carry[$item['order_id']];
        $carry[$item['order_id']] = [
            'order_id'      => $preItem['order_id'],
            'ids'           => array_merge($preItem['ids'], [ $item['id'] ]),
            'adm_aftr_disc' => $preItem['adm_aftr_disc']   $item['adm_aftr_disc'],
            'sup_aftr_disc' => $preItem['sup_aftr_disc']   $item['sup_aftr_disc'],
            'discount'      => $preItem['discount']   $item['discount'],
            'prod_disc'     => $preItem['prod_disc']   $item['prod_disc']
        ];
      } else {
        $carry[$item['order_id']] = [
            'order_id'      => $item['order_id'],
            'ids'           => [ $item['id'] ],
            'adm_aftr_disc' => $item['adm_aftr_disc'],
            'sup_aftr_disc' => $item['sup_aftr_disc'],
            'discount'      => $item['discount'],
            'prod_disc'     => $item['prod_disc']
        ];
      }
      return $carry;
    },
    []
);

Output:

Array
(
    [1] => Array
        (
            [order_id] => 1
            [ids] => Array
                (
                    [0] => 2
                    [1] => 1
                )

            [adm_aftr_disc] => 29.52
            [sup_aftr_disc] => 263.42
            [discount] => 62.06
            [prod_disc] => 4
        )

    [2] => Array
        (
            [order_id] => 2
            [ids] => Array
                (
                    [0] => 4
                    [1] => 3
                )

            [adm_aftr_disc] => 57.8
            [sup_aftr_disc] => 515.71
            [discount] => 121.49
            [prod_disc] => 4
        )

)

Note that the key of the main array are the same as the order_ids. So you can get details like this:

$adm_aftr_disc = $result[2]['adm_aftr_disc'];  // sum of adm_aftr_disc for order_id 2
  • Related