Использование std:: accumulate на двумерном std:: array
Для двумерного массива
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>')
Как я могу изящно вычислить эту сумму для моего 2D-массива (избегая for-loops, предпочитая STL-алгоритмы)?
Можно ли сделать однострочный, как для одномерного случая, или он становится более сложным?
Ответы
Ответ 1
Это немного сложнее. Вы должны вложить 2 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);
});
Это решение С++ 14 из-за общей лямбда, но для С++ 11 вам просто нужно явно указать типы.
Ответ 2
Концептуально вы хотите сгладить массив m
, а затем примените его к нему.
Используя библиотеку 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
Это работает так, как упоминал Пит Беккер в комментарии: "Проходите через одну строку массива и когда он попадает в конец строки, переходите к следующей строке". Никакой копии сделанных поддиапазонов.