up vote 0 down vote favorite

Hello. I have an array like this:

Array
(
    [1000] => Array
        (
            [pv] => 36
        )

    [1101] => Array
        (
            [1102] => Array
                (
                    [pv] => 92
                )

            [pv] => 38
        )

    [pv] => 64
)

How I can find the sum of all array elements with key 'pv', regardless of the depth at which they appear.

For this example the result will 36+92+38+64 = 240

Thanks for help.

link|flag

3  
The sum of those values should actually be 230 rather than 240 – Mark Baker Sep 23 at 12:06
1  
:) I have seen that array before – xtofl Sep 23 at 12:23

8 Answers

up vote 12 down vote accepted

Another alternative:

$sum = 0;
$array_obj = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($array_obj as $key => $value) {
    if($key == 'pv')
        $sum += $value;
}
echo $sum;

Update: Just thought I'd mention that this method uses the PHP SPL Iterators.


Salathe Edit:

A simple (relatively) way to filter the keys and to sum the values (without writing a custom Iterator) would be to do some filtering with a RegexIterator, convert the resulting iterator into an array and use the handy array_sum function on it. This is purely an academic exercise and I certainly wouldn't advocate it as the best way to achieve this... however, it is just one line-of-code. :)

$sum = array_sum(
    iterator_to_array(
        new RegexIterator(
            new RecursiveIteratorIterator(
                new RecursiveArrayIterator($array)
            ),
            '/^pv$/D',
            RegexIterator::MATCH,
            RegexIterator::USE_KEY
        ),
        false
    )
);
link|flag
+1! This one is nice, too! It does not require an extra function and does not clutter up the namespace. I like it! – elusive Sep 23 at 12:11
+1 for IteratorIterator I recently used this for directory traversing to find certain files with the RegexIteratorIterator. – Chris Sep 23 at 12:18
1  
+1: Plus, you could even toss in a FilterIterator and not have to worry about the if($key == 'pv')`part... But this is on the mark either way... – ircmaxell Sep 23 at 12:27
2  
@ircmaxell,@erisco Cue ridiculous one-liner... $sum = array_sum(iterator_to_array(new RegexIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)), '/^pv$/D', RegexIterator::MATCH,RegexIterator::USE_KEY), false)); – salathe Sep 24 at 8:45
1  
Yeah, that's ridiculous. An awesome display of what you can do with SPL, but still ridiculous. – ircmaxell Sep 24 at 11:07
show 2 more comments
up vote 5 down vote
function addPV($array){
  $sum = 0;
  foreach($array as $key => $a){
    if (is_array($a)){
       $sum += addPV($a);
    }else if($key == 'pv') {
       $sum += $a;
    }
  }
  return $sum;
}
link|flag
1  
+1! I hate passing function names as string as required for array_reduce(), etc. Nice and clean solution! – elusive Sep 23 at 12:00
3  
@elusive: in PHP5.3 you can just pass anonymous functions (like javascript tends to do), maybe that's less creepy to you: $arr = range(1,40); var_dump(array_reduce($arr,function($v,$k){return $v+$k;})); – Wrikken Sep 23 at 12:05
@Wrikken: Thats right, but you cannot assume that PHP 5.3 is already running everywhere. AFAIK, 5.3 will ship with the next release of debian at the earliest. fredleys solution works nicely with currently used versions of PHP and i consider it less ugly than the array_reduce() method. – elusive Sep 23 at 12:10
Afaik, 5.3.2 is in the testing branch, so in Debian terms that will be 'soonish', and I'm not disputing this is a nice solution (+1 'ed it), just reacted to your 'I don't like to pass function names as string' with some info you might be happy with in future in case you didn't know already ;) – Wrikken Sep 23 at 13:01
@Wrikken: Yes, thanks ;) – elusive Sep 23 at 13:11
up vote 3 down vote

you can use array_reduce or array_walk_recursive functions and a custom call back function of yourself:

function sum($v, $w)
{
    $v += $w;
    return $v;
}

$total = array_reduce($your_array, "sum");
link|flag
up vote 2 down vote

based on @Ali Sattari answer

function sum($v, $w) {
    return $v + (is_array($w) ? 
        array_reduce($w, __FUNCTION__) : $w);
}
link|flag
up vote 1 down vote
$sum = 0;

function sumArray($item, $key, &$sum)
{
    if ($key == 'pv')
       $sum += $item;
}

array_walk_recursive($array, 'sumArray',&$sum);
echo $sum;
link|flag
Works as long as there are nothing other than arrays and numbers with the key pv. – fredley Sep 23 at 11:55
@fredley - if the OP has additional criteria (eg test for booleans, etc) they can easily be added to the sumArray callback function – Mark Baker Sep 23 at 11:57
up vote 1 down vote
$array = array('1000'=> array('pv'=>36), array('1101' => array('pv'=>92)));

$total = 0;
foreach(new recursiveIteratorIterator( new recursiveArrayIterator($array)) as $sub)
{
 $total += (int)  $sub;
}
print_r($total);
link|flag
up vote 1 down vote
function SumRecursiveByKey($array,$key)
{
    $total = 0;
    foreach($array as $_key => $value)
    {
        if(is_array($value))
        {
            $total += SumRecursiveByKey($array,$key);
        }elseif($_key == $key)
        {
             $total += $value;
        }
    }
    return $total;
}

use like

$summed_items = SumRecursiveByKey($myArray,'pv');

This would give you more leeway in checking alternative keys a swell.

link|flag
up vote -1 down vote
private function calculateUserGv($userId) {
    $group = $this->arrayUnder($this->_user_tree, $userId);
    global $gv;
    $gv = 0;
    $gv    = $this->gvRecursive($group);
    return;
}

private function gvRecursive($group) {
    global $gv;
    foreach ($group as $key => $val) {
        if ($key == 'pv') {
            $gv += $group[$key];
        }
        else {
            $this->gvRecursive($val);
        }
    }
    return $gv;
}
link|flag
having global $gv, modifying it within the function, then return $gv is not nice. Invoking this function with $gv = $this->gvRecursive($group); is not nice at all. – fredley Sep 23 at 11:54

Your Answer

get an OpenID
or
never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.