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?

3
  • 2
    What's your desired outcome? 21 or {9, 12}? Commented Jun 28, 2017 at 16:17
  • My desired outcome is 21. Commented Jun 28, 2017 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) Commented Jun 28, 2017 at 17:11

3 Answers 3

23

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

1 Comment

Nice, I'm starting to like Ranges :-) Unfortunately, we're currently still stuck with VS2012, so only a few C++11 features available :-(
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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.