5

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 be 36+92+38+64 = 230

1

8 Answers 8

22

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

8 Comments

+1! This one is nice, too! It does not require an extra function and does not clutter up the namespace. I like it!
+1 for IteratorIterator I recently used this for directory traversing to find certain files with the RegexIteratorIterator.
+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,@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));
Yeah, that's ridiculous. An awesome display of what you can do with SPL, but still ridiculous.
|
12
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;
}

4 Comments

+1! I hate passing function names as string as required for array_reduce(), etc. Nice and clean solution!
@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: 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.
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 ;)
7

based on @Ali Sattari answer

function sum($v, $w) {
    return $v + (is_array($w) ? 
        array_reduce($w, __FUNCTION__) : $w);
}

Comments

4

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

1 Comment

i like this way, but dont you need conditional to check that key is pv? could be other numerical values
2
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.

Comments

1
$sum = 0;

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

array_walk_recursive($array, 'sumArray',&$sum);
echo $sum;

2 Comments

Works as long as there are nothing other than arrays and numbers with the key pv.
@fredley - if the OP has additional criteria (eg test for booleans, etc) they can easily be added to the sumArray callback function
1
$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);

Comments

-1
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;
}

1 Comment

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.

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.