如何对多维数组中的所有列值求和?

146

如何按关联键添加所有列值?请注意,键集是动态的。

输入数组:

Array
(
    [0] => Array
        (
            [gozhi] => 2
            [uzorong] => 1
            [ngangla] => 4
            [langthel] => 5
        )

    [1] => Array
        (
            [gozhi] => 5
            [uzorong] => 0
            [ngangla] => 3
            [langthel] => 2
        )

    [2] => Array
        (
            [gozhi] => 3
            [uzorong] => 0
            [ngangla] => 1
            [langthel] => 3
        )
)

期望的结果:

Array
(
    [gozhi] => 10
    [uzorong] => 1
    [ngangla] => 8
    [langthel] => 10
)

对于一般情况,两个多维数组的键并不完全相同。合并/求和PHP多维数组 - LF00
20个回答

228
您可以使用 array_walk_recursive() 来获取您的问题的通用解决方案(当每个内部数组可能具有唯一键时)。
$final = array();

array_walk_recursive($input, function($item, $key) use (&$final){
    $final[$key] = isset($final[$key]) ?  $item + $final[$key] : $item;
});

使用 array_walk_recursive() 处理一般情况的示例

此外,自PHP 5.5起,您可以使用array_column()函数来实现您想要的结果,对于精确的键[gozhi],例如:

array_sum(array_column($input, 'gozhi')); 

使用指定键值的 array_column() 的示例

如果您想要获取具有相同键的所有内部数组的总和(您发布的所需结果),您可以这样做(请记住第一个内部数组必须与其它数组具有相同的结构):

$final = array_shift($input);

foreach ($final as $key => &$value){
   $value += array_sum(array_column($input, $key));
}    

unset($value);

使用array_column()示例,针对所有内部数组具有相同键的情况

如果您想使用array_column()获得通用解决方案,则首先可以考虑获取所有唯一键,然后为每个键获取总和:

$final = array();

foreach($input as $value)
    $final = array_merge($final, $value);

foreach($final as $key => &$value)
    $value = array_sum(array_column($input, $key));

unset($value);

使用array_column()展示一般情况的示例


102
$sumArray = array();

foreach ($myArray as $k=>$subArray) {
  foreach ($subArray as $id=>$value) {
    isset($sumArray[$id]) || $sumArray[$id] = 0;
    $sumArray[$id]+=$value;
  }
}

print_r($sumArray);

3
对我来说,array_reduce听起来最好。https://dev59.com/nGYq5IYBdhLWcg3wzDhI - Bill'o

66

请使用以下片段:

$key = 'gozhi';
$sum = array_sum(array_column($array,$key));

1
我已经编辑了问题,以澄清这个解决方案在提供OP所需的输出方面有些不足。 话虽如此,如果您扩展您的答案,它很可能会成为早期发布的答案的重复。 - mickmackusa

28

这里有一个类似于其他两个解决方案的解决方案:

$acc = array_shift($arr);
foreach ($arr as $val) {
    foreach ($val as $key => $val) {
        $acc[$key] += $val;
    }
}

但是这并不需要检查数组键是否已经存在,也不会抛出警告。


这是一个非常聪明的解决方案,适用于特定的数组结构。但遗憾的是,在数组都像最终结果结构一样的更一般情况下,它无法正常工作。 - Todd Chaffee

22

也可以使用array_map来完成:

$rArray = array(
    0 => array(
        'gozhi' => 2,
        'uzorong' => 1,
        'ngangla' => 4,
        'langthel' => 5
    ),
    1 => array(
        'gozhi' => 5,
        'uzorong' => 0,
        'ngangla' => 3,
        'langthel' => 2
    ),
    2 => array(
        'gozhi' => 3,
        'uzorong' => 0,
        'ngangla' => 1,
        'langthel' => 3
    ),
);

$sumResult = call_user_func_array('array_map', array_merge(['sum'], $rArray));

function sum()
{
    return array_sum(func_get_args());
}

1
这个程序根据列的位置来求和--而不是根据列名/键。此答案还会从输出中去掉关联键。如果列已经对齐,并且结果可以是索引数组的索引数组,那么此答案才是合适的。https://3v4l.org/v0Tk3 这里是使用splat运算符的等效代码。https://3v4l.org/9hM3V - mickmackusa

13
$newarr=array();
foreach($arrs as $value)
{
  foreach($value as $key=>$secondValue)
   {
       if(!isset($newarr[$key]))
        {
           $newarr[$key]=0;
        }
       $newarr[$key]+=$secondValue;
   }
}

3
请注意,每次在右侧分配中访问$newarr[$key]且这些值尚不存在时,您将收到PHP通知(未定义索引)。 - Anti Veeranna
我认为我需要添加一个检查来初始化$newarr[$key]。 - Graviton
4
如果你投票反对某人,请留下评论...如果你不留下评论,就没有办法改进解决方案。 - Todd Chaffee
@Graviton 我没有给你的回答点踩,但我想说每个 StackOverflow 的回答都应该包含一些解释,说明这个解决方案是如何工作的,或者为什么这样做是可取的。请记住,这个网站/网络上的每一页都是成千上万的开发人员的教育资源,他们具有各种技能和知识水平。(如果我每次发现只有代码的答案就点踩,我的声望分数会用完的。) - mickmackusa

5

另一个版本,以下是一些优点。

$sum = ArrayHelper::copyKeys($arr[0]);

foreach ($arr as $item) {
    ArrayHelper::addArrays($sum, $item);
}


class ArrayHelper {

    public function addArrays(Array &$to, Array $from) {
        foreach ($from as $key=>$value) {
            $to[$key] += $value;
        }
    }

    public function copyKeys(Array $from, $init=0) {
        return array_fill_keys(array_keys($from), $init);
    }

}

我希望将Gumbo、Graviton和Chris J的答案优化结合,并实现以下目标,以便在我的应用程序中使用:

a)在循环外初始化“sum”数组键(Gumbo)。这应该有助于处理非常大的数组(尚未测试!)。消除通知。

b)主要逻辑易于理解,无需查阅手册(Graviton,Chris J)。

c)解决任何两个具有相同键的数组值相加的更一般问题,并使其不那么依赖子数组结构。

与Gumbo的解决方案不同,您可以在值不在子数组中的情况下重复使用它。想象一下,在下面的示例中,$arr1$arr2不是硬编码的,而是在循环内调用函数返回的结果。

$arr1 = array(
    'gozhi' => 2,
    'uzorong' => 1,
    'ngangla' => 4,
    'langthel' => 5
);

$arr2 = array(
   'gozhi' => 5,
   'uzorong' => 0,
   'ngangla' => 3,
   'langthel' => 2
);

$sum = ArrayHelper::copyKeys($arr1);

ArrayHelper::addArrays($sum, $arr1);
ArrayHelper::addArrays($sum, $arr2);

4

也可以使用array_walk来完成:

function array_sum_values(array $input, $key) {
   $sum = 0;
   array_walk($input, function($item, $index, $params) {
         if (!empty($item[$params[1]]))
            $params[0] += $item[$params[1]];
      }, array(&$sum, $key)
   );
   return $sum;
}

var_dump(array_sum_values($arr, 'gozhi'));

不像之前的解决方案那样易读,但它确实有效 :)


4

遍历数组中的每个元素,如果之前有值,则将当前值与之前的值相加,否则直接赋值。

<?php
$array = 
[
    [
        'a'=>1,
        'b'=>1,
        'c'=>1,
    ],
    [
        'a'=>2,
        'b'=>2,
    ],
    [
        'a'=>3,
        'd'=>3,
    ]
];

$result = array_reduce($array, function($carry, $item) {
    foreach($item as $k => $v)
        $carry[$k] = $v + ($carry[$k] ?? 0);

    return $carry;
}, []);

print_r($result);

输出:

Array
(
    [a] => 6
    [b] => 3
    [c] => 1
    [d] => 3
)

或者只需循环遍历每个子数组,并为每列分组值。最终将它们加起来:
foreach($array as $subarray)
    foreach($subarray as $key => $value)
        $grouped[$key][] = $value;

$sums = array_map('array_sum', $grouped);

3
我们需要先检查数组键是否存在。 代码:
$sum = array();
foreach ($array as $key => $sub_array) {
    foreach ($sub_array as $sub_key => $value) {

        //If array key doesn't exists then create and initize first before we add a value.
        //Without this we will have an Undefined index error.
        if( ! array_key_exists($sub_key, $sum)) $sum[$sub_key] = 0;

        //Add Value
        $sum[$sub_key]+=$value;
    }
}
print_r($sum);

使用数组键验证的输出:

Array
(
    [gozhi] => 10
    [uzorong] => 1
    [ngangla] => 8
    [langthel] => 10
)

没有数组键验证的输出:

Notice: Undefined index: gozhi in F:\web\index.php on line 37

Notice: Undefined index: uzorong in F:\web\index.php on line 37

Notice: Undefined index: ngangla in F:\web\index.php on line 37

Notice: Undefined index: langthel in F:\web\index.php on line 37

Array
(
    [gozhi] => 10
    [uzorong] => 1
    [ngangla] => 8
    [langthel] => 10
)

虽然它能输出结果,但这是一种不好的做法。在使用之前,始终先检查键是否存在。


我使用了这个,但是出现了一个错误:遇到了非数字值。 - Hedayatullah Sarwary

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