在一个二维的std::array上使用std::accumulate

12

给定一个二维数组

std::array<std::array<int, 2>, 3> m = {{ {1, 2}, {3, 4}, {5, 6} }};
我正在寻找其所有元素的总和 - 在这种情况下是21。如果该数组是一维的,我可以写出以下代码:
auto sum = std::accumulate(m.begin(), m.end(), 0);

但是对于我的二维数组,这会失败并返回一个相当易于理解的错误。

no match for 'operator+' (operand types are 'int' and 'std::array<int, 2ul>')

如何优雅地计算我的二维数组的总和(避免使用 for 循环,更喜欢 STL 算法)?

是否可以通过一行代码解决,就像一维情况一样,还是会变得更加复杂?


2
你的期望结果是什么?是 21 还是 {9, 12} - Barry
我的期望结果是21。 - Bart Vandewoestyne
2
我没有精力去处理细节,但是你可以编写一个迭代器,它知道如何遍历二维数组。基本上,它会遍历数组的一行,当它到达该行的末尾时,移动到下一行。这比Rakete111嵌套调用std::accumulate更棘手,但它更通用:您可以将该迭代器用于任何算法。(如果有人想处理细节,请随时将您的代码发布为答案) - Pete Becker
3个回答

22

这只是有点更加复杂。你需要嵌套两个std::accumulate调用。嵌套的std::accumulate调用会对嵌套数组中的元素求和,然后第一个std::accumulate会将它们加总。

auto sum = std::accumulate(m.cbegin(), m.cend(), 0, [](auto lhs, const auto& rhs) {
    return std::accumulate(rhs.cbegin(), rhs.cend(), lhs);
});

这是一个C++14的解决方案,因为使用了泛型lambda表达式,但对于C++11,您只需要显式指定类型即可。


10

概念上,您希望“压平”数组m,然后对其应用accumulate函数。
使用Range-v3库(或将来的Ranges TS),您可以轻松做到这一点。(链接到wandbox).

std::array<std::array<int, 2>, 3> m = {{ {1, 2}, {3, 4}, {5, 6} }};

auto result = ranges::accumulate(ranges::join(m), 0); // flatten range then apply accumulate

这就像Pete Becker在评论中提到的那样工作:“遍历一行数组,当它到达行末尾时,移动到下一行”。没有制作子范围的副本。


很好,我开始喜欢Ranges :-) 不幸的是,我们目前仍然被困在VS2012中,所以只有一些C++11功能可用 :-( - Bart Vandewoestyne

1
请尝试以下操作:

请按照以下方式进行:

std::unique_ptr<int[][Column]> matrix (new int[Row][Column]);
long long total = 0;
for(int i=0; i < Row; i++){
total =  std::accumulate(std::begin(matrix[i]),std::end(matrix[i]),total);
}

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