2017-06-28 22 views
11

Biorąc pod tablicą dwuwymiarowąUżywanie std :: gromadzą się na dwuwymiarowej std :: array

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

szukam sumy wszystkich jego elementów - w tym przypadku 21. Gdyby tablicę były jednowymiarowe, mogłem napisany

auto sum = std::accumulate(m.begin(), m.end(), 0); 

ale dla mojej tablicy dwuwymiarowej, to się nie powiedzie się z powodu błędu raczej zrozumiały

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

Jak mogę elegancko obliczyć tę sumę dla mojej tablicy 2D (unikając pętli for, preferując algorytmy STL)?

Czy można to zrobić za pomocą jednego liniowca, jak w przypadku jednowymiarowym, czy też staje się on bardziej złożony?

+2

Jaki jest twój pożądany rezultat? '21' lub' {9, 12} '? – Barry

+0

Pożądany wynik to 21. –

+2

Nie mam energii do opracowania szczegółów, ale możesz napisać iterator, który wie, jak przejść przez dwuwymiarową tablicę. Zasadniczo przejdzie on przez jeden rząd tablicy i kiedy dotrze do końca wiersza, przejdź do następnego wiersza. To trochę trudniejsze do napisania niż zagnieżdżone wywołania Rakete111 do 'std :: accumulate', ale jest bardziej ogólne: możesz użyć tego iteratora dla ** dowolnego algorytmu **. (Jeśli ktoś chce dopracować szczegóły, napisz swój kod jako odpowiedź) –

Odpowiedz

19

Jest to nieco bardziej skomplikowane. Musisz zagnieździć 2 std::accumulate. Zagnieżdżone wywołanie std::accumulate sumuje elementy w zagnieżdżonych tablicach, a następnie pierwszy std::accumulate podsumowuje je.

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

To jest rozwiązanie C++ 14 ze względu na ogólną lambdę, ale w C++ 11, wystarczy określić typy jawnie.

6

Konceptualnie chcesz spłaszczyć tablicę m, a następnie zastosować akumulować do niego.
Korzystanie z biblioteki Range-v3 (lub Ranges TS w przyszłości) można wykonać tylko w ten sposób: (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 

To działa jak co Pete Becker wspomniano w komentarzu: „spacer po jednym wierszu tablicy i kiedy trafi do końca rzędu, przejść do następnego wiersza”. Nie utworzono kopii podzbiorów.

+0

Fajnie, zaczynam lubić zakresy :-) Niestety, wciąż mamy problem z VS2012, więc tylko kilka C + Dostępnych jest +11 funkcji :-( –

Powiązane problemy