Given the two-dimensional array
std::array<std::array<int, 2>, 3> m = {{ {1, 2}, {3, 4}, {5, 6} }};
I am looking for the sum of all its elements - in this case, 21. Had the array been one-dimensional, I could've written
auto sum = std::accumulate(m.begin(), m.end(), 0);
but for my two-dimensional array, this fails with the rather understandable error
no match for 'operator+' (operand types are 'int' and 'std::array<int, 2ul>')
How can I elegantly compute this sum for my 2D array (avoiding for-loops, preferring STL-algorithms)?
Can it be done with a one-liner like for the one-dimensional case, or does it become more complex?
It's just a bit more complex. You have to nest 2 std::accumulate
calls. The nested std::accumulate
call sums the elements in the nested arrays, and then the first std::accumulate
sums those up.
auto sum = std::accumulate(m.cbegin(), m.cend(), 0, [](auto lhs, const auto& rhs) {
return std::accumulate(rhs.cbegin(), rhs.cend(), lhs);
});
That's a C++14 solution because of the generic lambda, but for C++11, you just need to specify the types explicitly.
Conceptually you want to flatten array m
and then apply accumulate to it.
Using Range-v3 library (or Ranges TS in the future) you can do just that (link to 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
That works like what Pete Becker mentioned in comment: "walk through one row of the array and when it hits the end of the row, move to the next row". No copy of subranges made.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With