1

I have a two-dimensional array like this:like this:

[
    ['city' => 'NewYork', 'cash' => 1000],
    ['city' => 'Philadelphia', 'cash' => 2300],
    ['city' => 'NewYork', 'cash' => 2000]
]

I'd like to sum the value cash of rows which share the same city value to form a result with the same 2d structure.

Desired result:

[
    ['city' => 'NewYork', 'cash' => 3000],
    ['city' => 'Philadelphia', 'cash' => 2300],
]
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • 1
    [`array_reduce()`](http://php.net/manual/en/function.array-reduce.php) to the rescue! – axiac Feb 15 '15 at 15:17

4 Answers4

2

Use function array_reduce() to combine the items having the same city:

$input = array(
    array('city' => 'NewYork',      'cash' => '1000'),
    array('city' => 'Philadelphia', 'cash' => '2300'),
    array('city' => 'NewYork',      'cash' => '2000'),
);

$output = array_reduce(
    // Process the input list
    $input,
    // Add each $item from $input to $carry (partial results)
    function (array $carry, array $item) {
        $city = $item['city'];
        // Check if this city already exists in the partial results list
        if (array_key_exists($city, $carry)) {
            // Update the existing item
            $carry[$city]['cash'] += $item['cash'];
        } else {
            // Create a new item, index by city
            $carry[$city] = $item;
        }
        // Always return the updated partial result
        return $carry;
    },
    // Start with an empty list
    array()
);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
axiac
  • 68,258
  • 9
  • 99
  • 134
  • The benefit to using this technique over a `foreach()` loop is that you don't _have to_ declare an output variable -- I mean you can nest the function call inside of `array_values()` and then inside of `var_export()` to display the result on screen. [Like this](http://sandbox.onlinephpfunctions.com/code/3db42a4e13464eb027d85549f897a313fb8250eb) I think the reason some people don't use `array_reduce()` is because the code block appears more convoluted (just takes a little getting used to). – mickmackusa Aug 05 '17 at 22:11
1

Using any more than one loop (or looping function) to sum the values is inefficient.

Here is a method that uses temporary keys to build the result array and then reindexes the result array after the loop terminates.

Code: (Demo) with no iterated function calls thanks to the "null coalescing operator"

foreach ($array as $row) {
    $result[$row['city']] = [
        'city' => $row['city'],
        'cash' => ($result[$row['city']]['cash'] ?? 0) + $row['cash']
    ];
}
var_export(array_values($result));

Code: (Demo) with references to avoid declaring first level grouping key and any globally scoped variables

var_export(
    array_reduce(
        $array,
        function($result, $row) {
            static $ref;
            if (!isset($ref[$row['city']])) {
                $ref[$row['city']] = $row;
                $result[] = &$ref[$row['city']];
            } else {
                $ref[$row['city']]['cash'] += $row['cash'];
            }
            return $result;
        }
    )
);

Code: (Demo)

foreach ($array as $a) {
    if (!isset($result[$a['city']])) {
        $result[$a['city']] = $a;  // store temporary city-keyed result array (avoid Notices)
    } else {
        $result[$a['city']]['cash'] += $a['cash'];  // add current value to previous value
    }
}
var_export(array_values($result));  // remove temporary keys
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

Try below code:

<?php

$arr = array(
        array('city' => 'NewYork', 'cash' => '1000'),
        array('city' => 'Philadelphia', 'cash' => '2300'),
        array('city' => 'NewYork', 'cash' => '2000'),
    );

$newarray = array();
foreach($arr as $ar)
{
    foreach($ar as $k => $v)
    {
        if(array_key_exists($v, $newarray))
            $newarray[$v]['cash'] = $newarray[$v]['cash'] + $ar['cash'];
        else if($k == 'city')
            $newarray[$v] = $ar;
    }
}

print_r($newarray);


Output:

Array
(
    [NewYork] => Array
        (
            [city] => NewYork
            [cash] => 3000
        )

    [Philadelphia] => Array
        (
            [city] => Philadelphia
            [cash] => 2300
        )

)


Demo:
http://3v4l.org/D8PME

Parag Tyagi
  • 8,780
  • 3
  • 42
  • 47
  • 4
    _Try this_ code-only answers are low-value on StackOverflow because they do a poor job of educating/empowering the OP and thousands of future researchers. Please edit this answer to explain what you've done and why it is a good idea. – mickmackusa Sep 12 '18 at 03:42
-1

Try this:

 $sumArray = array();

    foreach ($arrTotal as $k=>$subArray) {

        foreach ($subArray as $id=>$value) {
            $sumArray[$subArray['city']]+=$value;
        }

    }

    var_dump($sumArray);

Output:

array(2) {
  ["NewYork"]=>
  int(3000)
  ["Philadelphia"]=>
  int(2300)
}
Whirlwind
  • 14,286
  • 11
  • 68
  • 157