36

Possible Duplicate:
PHP: How to sum values of the array of the same key

I am looking for an array_merge() function that does NOT replace values, but ADDS them.

Example, this is the code I am trying:

    echo "<pre>"; 

    $a1 = array(
         "a" => 2
        ,"b" => 0
        ,"c" => 5
    );

    $a2 = array(
         "a" => 3
        ,"b" => 9
        ,"c" => 7
        ,"d" => 10
    );

    $a3 = array_merge($a1, $a2);
    print_r($a3); 

Sadly, this outputs this:

Array
(
    [a] => 3
    [b] => 9
    [c] => 7
    [d] => 10
)

I then tried, instead of array_merge, just simply adding the two arrays

$a3 = $a1 + $a2;

But this outputs

Array
(
    [a] => 2
    [b] => 0
    [c] => 5
    [d] => 10
)

What I truly want is to be able to pass as many arrays as needed, and then get their sum. So in my example, I want the output to be:

Array
(
    [a] => 5
    [b] => 9
    [c] => 12
    [d] => 10
)

Of course I can schlepp and build some function with many foreach etc, but am looking or a smarter, cleaner solution. Thanks for any pointers!

Community
  • 1
  • 1
Erick
  • 369
  • 1
  • 3
  • 4
  • 2
    This sounds like the kind of thing you want to write a function for. I wouldn't consider it "schlepping" by any means, this is a fairly unique thing to want to do. I could be proven wrong however, but I don't believe there's any native function that can handle this by itself. If writing a function is the solution, do you still need help? – Wesley Murch May 22 '11 at 05:44
  • I believe there is no built-in function that can do this, check this question: http://stackoverflow.com/questions/1496682/php-how-to-sum-values-of-the-array-of-the-same-key – Yuri Stuken May 22 '11 at 05:45
  • 2
    The question is formulated wrong. `array_merge` does *merge two arrays while retaining **all** keys*. But you want to *sum the **value** of identical keys of two arrays*, which is something else. – deceze May 22 '11 at 06:26
  • [merge/sum multi dimentional array php](https://stackoverflow.com/q/44607229/6521116) – LF00 Jun 17 '17 at 17:59

3 Answers3

69
$sums = array();
foreach (array_keys($a1 + $a2) as $key) {
    $sums[$key] = (isset($a1[$key]) ? $a1[$key] : 0) + (isset($a2[$key]) ? $a2[$key] : 0);
}

You could shorten this to the following using the error suppression operator, but it should be considered ugly:

$sums = array();
foreach (array_keys($a1 + $a2) as $key) {
    $sums[$key] = @($a1[$key] + $a2[$key]);
}

Alternatively, some mapping:

$keys = array_fill_keys(array_keys($a1 + $a2), 0);
$sums = array_map(function ($a1, $a2) { return $a1 + $a2; }, array_merge($keys, $a1), array_merge($keys, $a2));

Or sort of a combination of both solutions:

$sums = array_fill_keys(array_keys($a1 + $a2), 0);
array_walk($sums, function (&$value, $key, $arrs) { $value = @($arrs[0][$key] + $arrs[1][$key]); }, array($a1, $a2));

I think these are concise enough to adapt one of them on the spot whenever needed, but to put it in terms of a function that accepts an unlimited number of arrays and sums them:

function array_sum_identical_keys() {
    $arrays = func_get_args();
    $keys = array_keys(array_reduce($arrays, function ($keys, $arr) { return $keys + $arr; }, array()));
    $sums = array();

    foreach ($keys as $key) {
        $sums[$key] = array_reduce($arrays, function ($sum, $arr) use ($key) { return $sum + @$arr[$key]; });
    }
    return $sums;
}
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 3
    Now why was this voted down, please? It may look cryptic, but only if you're not used to thinking in sets and functions. IMO it's a lot more elegant than nested loops or tons of `if`s. – deceze May 22 '11 at 07:08
  • 2
    Third solution reseted array keys for me. – Volvox Jan 24 '14 at 16:39
  • Why we are checking like `(isset($a1[$key]) ? $a1[$key] : 0)` in 1st function? Can we directly do like `$a1[$key] + $a2[$key]` in that function like 2nd function? – G_real Sep 06 '19 at 20:58
  • @viren To avoid *undefined index* notices if both arrays don’t contain the same keys. In the second version we use the error suppression operator instead for that purpose. – deceze Sep 07 '19 at 05:58
16

My contribution:

function array_merge_numeric_values()
{
    $arrays = func_get_args();
    $merged = array();
    foreach ($arrays as $array)
    {
        foreach ($array as $key => $value)
        {
            if ( ! is_numeric($value))
            {
                continue;
            }
            if ( ! isset($merged[$key]))
            {
                $merged[$key] = $value;
            }
            else
            {
                $merged[$key] += $value;
            }
        }
    }
    return $merged;
}

Pass as many arrays to it as you want. Feel free to add some more defense, ability to accept multidimensional arrays, or type checking.

Demo: http://codepad.org/JG6zwAap

Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
6

its not so complicate do something like:

$a3 = $a1;

foreach($a2 as $k => $v) {
    if(array_key_exists($k, $a3)) {
       $a3[$k] += $v;
    } else {
       $a3[$k] = $v; 
    }
}
Warren Sergent
  • 2,542
  • 4
  • 36
  • 42
Haim Evgi
  • 123,187
  • 45
  • 217
  • 223