Ecko Santoso
Ecko Santoso

Reputation: 521

Group qualifying multidimensional array data and sum a column of values

I have an array with dynamic values. The goal is to merge the subarrays which have same code and sum of cost value with same code.

$array = [
    [
        ['code'=>'AA', 'name'=>'A Name', 'cost'=>'10'],
        ['code'=>'AB', 'name'=>'B Name', 'cost'=>'15'],
    ],
    [
        ['code'=>'AA', 'name'=>'A Name', 'cost'=>'15'],
        ['code'=>'AB', 'name'=>'B Name', 'cost'=>'10'],
        ['code'=>'AC', 'name'=>'C Name', 'cost'=>'10'],
    ],
    [
        ['code'=>'AA', 'name'=>'A Name', 'cost'=>'5'],
        ['code'=>'AB', 'name'=>'B Name', 'cost'=>'10'],
        ['code'=>'AC', 'name'=>'C Name', 'cost'=>'15'],
    ]
];

Desired result:

[
    [
        ['code'=>'AA', 'name'=>'A Name', 'cost'=>'30'],
        ['code'=>'AB', 'name'=>'B Name', 'cost'=>'35'],
    ]
]

The result is only code AA and BB because code AC not exist on first index. Then cost values within each group are summed.

Upvotes: 0

Views: 75

Answers (5)

JokJa
JokJa

Reputation: 36

Demo

$array = array(
            array(
                array(
                    'code'=>'AA',
                    'name'=>'A Name',
                    'cost'=>'10',
                ),
                array(
                    'code'=>'AB',
                    'name'=>'B Name',
                    'cost'=>'15',
                ),
            ),
            array(
                array(
                    'code'=>'AA',
                    'name'=>'A Name',
                    'cost'=>'15',
                ),
                array(
                    'code'=>'AB',
                    'name'=>'B Name',
                    'cost'=>'10',
                ),
                array(
                    'code'=>'AC',
                    'name'=>'C Name',
                    'cost'=>'10',
                ),
            ),
            array(
                array(
                    'code'=>'AA',
                    'name'=>'A Name',
                    'cost'=>'5',
                ),
                array(
                    'code'=>'AB',
                    'name'=>'B Name',
                    'cost'=>'10',
                ),
                array(
                    'code'=>'AC',
                    'name'=>'C Name',
                    'cost'=>'15',
                ),
            ),
        );      

        $the_biggest_number=count($array);

        $new_array = array();
        foreach ($array as $key => $val) {

            foreach ($val as $sub_key => $sub_val) {
                if(!isset($new_array[$sub_val['code']])){
                        $sub_val['count']=1;
                        $new_array[$sub_val['code']]=$sub_val;
                }
                else{
                    $new_array[$sub_val['code']]['cost'] += $sub_val['cost'];
                    $new_array[$sub_val['code']]['count'] += 1;
                }
            }
        }        

        $result=array();
        foreach ($new_array as $key => $val) {
            if($val['count']==$the_biggest_number){
                unset($val['count']);
                $result[]=$val;
            }
        }

        $result= array($result);

        echo '<pre>';
        print_r($result);

Upvotes: 2

Оzgur
Оzgur

Reputation: 432

UPDATED

<?php

$collection = array(
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'15',
        ),
        array(
            'code'=>'AD',
            'name'=>'D Name',
            'cost'=>'45',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'15',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'10',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'5',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'15',
        ),
    ),
);

$newcollection=array();
$keysregistered=array();
$i=1;
foreach($collection as $list) {
    $collectionkeys = array();
    foreach($list as $arr) {
        $key=$arr['code'];
        $collectionkeys[]=$key;
        if(isset($keysregistered[$key])) {
             $oldtotal = $keysregistered[$key];
             $total = $oldtotal+$arr['cost'];
             $newcollection[$key]['cost'] = $total;
        } else {
             if($i==1) {
                 $newcollection[$key] = $arr;
                 $keysregistered[$key] = $arr['cost'];
             }
        }
    }

    $registeredkeys = array_keys($keysregistered);
    $diff = array_diff($registeredkeys,$collectionkeys);
    foreach($diff as $delkey) {
        unset($keysregistered[$delkey],$newcollection[$delkey]);
    }
$i++;
}

$finalarr = array_values($newcollection);

print_r($finalarr);


?>

Now code is updated, it will even remove AD from the first item and give you totals for unique codes.

Upvotes: 0

Akshay Hegde
Akshay Hegde

Reputation: 16997

Its simple, here is a way

<?php
    $codes = array_column($array[0],"code");
    $out =array();
    foreach($array as $main)
    {
        foreach($main as $sub)
        {
            if(in_array($sub['code'], $codes))
            {
                if(isset($out[$sub['code']]))
                {
                    $out[$sub['code']]['cost']+=$sub['cost'];
                }else
                {
                    $out[$sub['code']] = $sub;
                }
            }       
        }       
    }
    print_r(array_values($out));
?>

Test Results

akshay@db-3325:/tmp$ cat test.php 
<?php
$array = array(
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'15',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'15',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'10',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'5',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'15',
        ),
    ),
);

    $codes = array_column($array[0],"code");
    $out =array();
    foreach($array as $main)
    {
        foreach($main as $sub)
        {
            if(in_array($sub['code'], $codes))
            {
                if(isset($out[$sub['code']]))
                {
                    $out[$sub['code']]['cost']+=$sub['cost'];
                }else
                {
                    $out[$sub['code']] = $sub;
                }
            }       
        }       
    }
    print_r(array_values($out));
?>

Output

akshay@db-3325:/tmp$ php test.php 
Array
(
    [0] => Array
        (
            [code] => AA
            [name] => A Name
            [cost] => 30
        )

    [1] => Array
        (
            [code] => AB
            [name] => B Name
            [cost] => 35
        )

)

Upvotes: 1

RomanPerekhrest
RomanPerekhrest

Reputation: 92904

The solution using array_column, array_map, call_user_func_array and array_merge functions:

// $arr is your initial array

$merged = call_user_func_array("array_merge", $arr);

// getting `code` keys from the first nested item
$result = array_map(function($v){
    return [];
}, array_column($arr[0], 'cost', 'code'));

foreach ($merged as $item) {
    if (isset($result[$item['code']])) {
        if ($result[$item['code']]) {
            $result[$item['code']]['cost'] += $item['cost'];
        } else {
            $result[$item['code']] = $item;
        }
    }
}
$result = [array_values($result)];

print_r($result);

The output:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [code] => AA
                    [name] => A Name
                    [cost] => 30
                )

            [1] => Array
                (
                    [code] => AB
                    [name] => B Name
                    [cost] => 35
                )
        )
)

Upvotes: 0

Sahil Gulati
Sahil Gulati

Reputation: 15141

PHP code demo

<?php
ini_set("display_errors", 1);
$array = array(
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'15',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'15',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'10',
        ),
    ),
    array(
        array(
            'code'=>'AA',
            'name'=>'A Name',
            'cost'=>'5',
        ),
        array(
            'code'=>'AB',
            'name'=>'B Name',
            'cost'=>'10',
        ),
        array(
            'code'=>'AC',
            'name'=>'C Name',
            'cost'=>'15',
        ),
    ),
);
$newData=array();
array_map(function($arrayData) use(&$newData){
    foreach($arrayData as $data => $value)
    {
        $newData[]=$value;
    }
}, $array);

$result=array();
array_map(function($data) use(&$result){
    // array("AA","AB") in this array you can add your code for which you want to merge.
    if(in_array($data["code"], array("AA","AB")))
    {
        if(!isset($result[$data["code"]]))
        {
            $result[$data["code"]]=$data;
        }
        else
        {
            $result[$data["code"]]["cost"]+=$data["cost"];
        }
    }

}, $newData);
$result=array(array_values($result));
print_r($result);

Output:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [code] => AA
                    [name] => A Name
                    [cost] => 30
                )

            [1] => Array
                (
                    [code] => AB
                    [name] => B Name
                    [cost] => 35
                )

        )

)

Upvotes: 0

Related Questions