0

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.

3
  • you meant AC, not CC Commented Apr 11, 2017 at 16:34
  • @Ecko I'm not 100% sure I understand the necessary rules based on the current sample array. Will it always be the first set of rows that dictates which codes will be kept? or might another set of rows also indicate what rows to disqualify? Is this example data possible? 3v4l.org/msaoj Commented Sep 21, 2022 at 4:38
  • @Ecko I'd like to post a new answer for you, but I don't know if 3v4l.org/AT3on is correct (because only checking the first set of rows is sufficient) or if checking for matching code values in ALL sets is required as 3v4l.org/FH58e. Commented Sep 21, 2022 at 6:07

5 Answers 5

2

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);
Sign up to request clarification or add additional context in comments.

Comments

1

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
        )

)

2 Comments

nice, but how is $codes = array_column($array[0],"code"); not in first index? column is dinamic
@EckoSantoso: I didn't get you, please explain, $codes = array_column($array[0],"code"); saves 'code' in first node to array $codes
0

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
                )

        )

)

Comments

0

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
                )
        )
)

1 Comment

This nice, but to many php function, this will take effect with php version
0

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.

1 Comment

@EckoSantoso code is updated, better than other answers as it even removes AD from first element of $array. you should give this a try

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.