2017-06-28 3 views
11

Compte tenu du tableau à deux dimensionsEn utilisant std :: accumuler sur un std :: tableau à deux dimensions

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

Je cherche la somme de tous ses éléments - dans ce cas, le tableau 21. Had été unidimensionnelle, je pourrais avoir écrit

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

mais pour mon tableau à deux dimensions, cette tentative échoue avec l'erreur plutôt compréhensible

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

Comment puis-je calculer avec élégance cette somme pour ma matrice 2D (en évitant les boucles for-loops, en préférant les algorithmes STL)? Peut-il être fait avec un doublure comme pour le cas unidimensionnel, ou devient-il plus complexe?

+2

Quel est votre résultat souhaité? '21' ou' {9, 12} '? – Barry

+0

Mon résultat escompté est de 21. –

+2

Je n'ai pas l'énergie pour élaborer les détails, mais vous pouvez écrire un itérateur qui sait comment parcourir un tableau à deux dimensions. Fondamentalement, il marcherait à travers une rangée du tableau et quand il atteint la fin de la rangée, passer à la rangée suivante. C'est un peu plus difficile à écrire que les appels imbriqués de Rakete111 à 'std :: accumulate', mais c'est plus général: vous pouvez utiliser cet itérateur pour l'algorithme ** any **. (Si quelqu'un veut travailler sur les détails, n'hésitez pas à poster votre code comme réponse) –

Répondre

19

C'est juste un peu plus complexe. Vous devez imbriquer 2 std::accumulate appels. L'appel imbriqué std::accumulate résume les éléments des tableaux imbriqués, puis le premier std::accumulate les additionne.

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

C'est une solution 14 C++ en raison du lambda générique, mais pour 11 C++, il vous suffit de spécifier les types explicitement.

6

Conceptuellement, vous souhaitez aplatir tableau m, puis lui appliquer accumuler.
En utilisant la bibliothèque Range-v3 (ou Ranges TS dans le futur), vous pouvez faire exactement cela (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 

qui fonctionne comme ce que Pete Becker mentionné dans le commentaire: « marcher à travers une ligne du tableau et quand il arrive à la fin de la ligne, passer à la ligne suivante ». Aucune copie des sous-domaines effectuée.

+0

Bien, je commence à aimer les gammes :-) Malheureusement, nous sommes toujours bloqués avec VS2012, donc seulement quelques C + +11 fonctionnalités disponibles :-( –