12

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?

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 2
    What's your desired outcome? `21` or `{9, 12}`? – Barry Jun 28 '17 at 16:17
  • My desired outcome is 21. – Bart Vandewoestyne Jun 28 '17 at 16:46
  • 2
    I don't have the energy to work out the details, but you can write an iterator that knows how to walk through a 2-dimensional array. Basically, it would walk through one row of the array and when it hits the end of the row, move to the next row. That's a little trickier to write than Rakete111's nested calls to `std::accumulate`, but it is more general: you can use that iterator for **any** algorithm. (If someone wants to work out the details, feel free to post your code as an answer) – Pete Becker Jun 28 '17 at 17:11

3 Answers3

22

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.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
10

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.

Serikov
  • 1,159
  • 8
  • 15
1

Please try as below :

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);
}
Aditya Kumar
  • 155
  • 6