如何递归地对一个特定的数组键求和?

5

我有一个像这样的数组:

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

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

            [pv] => 38
        )

    [pv] => 64
)

我如何找到所有键为“pv”的数组元素的总和,而不管它们出现在哪个深度?
对于这个例子,结果将是36+92+38+64 = 230

Medoo:http://stackoverflow.com/questions/3777134/php-get-subarray-from-array-by-key,https://dev59.com/JlDTa4cB1Zd3GeqPLKsx,... - Wernight
8个回答

22

另一个选择:

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

更新:只是想提一下,这种方法使用了PHP的SPL迭代器


Salathe编辑:

一个简单(相对而言)的过滤键并求和值的方法(不需要编写自定义迭代器)是使用RegexIterator进行一些过滤,将结果迭代器转换为数组并在其上使用方便的array_sum函数。这纯粹是一种学术练习,我肯定不会把它作为实现此目的的最佳方法...但是,它只需要一行代码。 :)

$sum = array_sum(
    iterator_to_array(
        new RegexIterator(
            new RecursiveIteratorIterator(
                new RecursiveArrayIterator($array)
            ),
            '/^pv$/D',
            RegexIterator::MATCH,
            RegexIterator::USE_KEY
        ),
        false
    )
);

+1!这个不错,它不需要额外的函数,也不会使命名空间混乱。我喜欢它! - jwueller
1
另外,您甚至可以添加一个FilterIterator,而不必担心if($key == 'pv')部分...但无论如何,这都是正确的... - ircmaxell
2
@ircmaxell,@erisco 请看这个荒谬的一行代码... $sum = array_sum(iterator_to_array(new RegexIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)), '/^pv$/D', RegexIterator::MATCH,RegexIterator::USE_KEY), false)); - salathe
1
是的,那太荒谬了。这是对SPL的惊人展示,但仍然荒谬。 - ircmaxell
哇!!正则表达式的方法真是太棒了!感谢您的帮助! - Everton Z. P.
显示剩余3条评论

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

1
+1!我讨厌像array_reduce()这样需要将函数名作为字符串传递的方式。这是一个简洁而干净的解决方案! - jwueller
3
在PHP5.3中,您可以像JavaScript一样传递匿名函数,也许这对您来说不那么令人困惑:$ arr = range(1,40); var_dump(array_reduce($ arr,function($ v,$ k){return $ v + $ k;})); - Wrikken
@Wrikken:没错,但你不能假设 PHP 5.3 已经在所有地方运行。据我所知,最早 5.3 将随 Debian 的下一个版本一起发布。Fredley 的解决方案可以很好地与当前使用的 PHP 版本配合使用,我认为它比 array_reduce() 方法更加优美。 - jwueller
据我所知,5.3.2版本目前在测试分支中,因此按照Debian的说法,这将很快推出。我并不否认这是一个好的解决方案(+1),只是针对你的“我不喜欢将函数名作为字符串传递”的反应,提供了一些你未来可能会感到满意的信息,以防你还不知道 ;) - Wrikken

7

基于@Ali Sattari的答案

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

4
你可以使用array_reducearray_walk_recursive函数和自定义的回调函数来实现:
function sum($v, $w)
{
    $v += $w;
    return $v;
}

$total = array_reduce($your_array, "sum");

我喜欢这种方式,但你不需要条件语句来检查键是否为“pv”吗?可能会有其他数字值。 - jon_darkstar

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

使用方法

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

这将使您在检查替代密钥方面有更多的余地。

1
$sum = 0;

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

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

只要键“pv”中除了数组和数字以外没有其他内容,就可以正常工作。 - fredley
@fredley - 如果原帖有额外的条件(例如测试布尔值等),它们可以轻松地添加到sumArray回调函数中。 - Mark Baker

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

-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
在函数内部修改 global $gv,然后返回它并不好。使用 $gv = $this->gvRecursive($group); 调用这个函数也不好。 - fredley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接