Quels sont les bons moyens de trouver la somme de tous les éléments dans un std::vector
?
Supposons que j'ai un vecteur std::vector<int> vector
contenant quelques éléments. Maintenant, je veux trouver la somme de tous les éléments. Quelles sont les différentes façons de faire la même chose?
std::accumulate
à Boost? (Si oui, pourquoi?) Recherchez-vous des fonctions qui font quelque chose de similairestd::accumulate
? (Si oui, quoi?)std::accumulate
, vous voudrez probablement aussi qu'il soit différent à certains égards (sinon vous pourriez simplement utiliserstd::accumulate
); Quelle (s) différence (s)std::accumulate
recherchez-vous?Réponses:
En fait, il existe plusieurs méthodes.
C ++ 03
Classique pour boucle:
En utilisant un algorithme standard:
Remarque importante: Le type du dernier argument est utilisé non seulement pour la valeur initiale, mais également pour le type du résultat . Si vous y mettez un int, il accumulera des ints même si le vecteur a flotté. Si vous additionnez des nombres à virgule flottante, passez
0
à0.0
ou0.0f
(grâce à nneonneo). Voir également la solution C ++ 11 ci-dessous.C ++ 11 et supérieur
b. Suivi automatique du type de vecteur, même en cas de modifications futures:
En utilisant
std::for_each
:Utilisation d'une boucle for basée sur une plage (grâce à Roger Pate):
la source
std::for_each
avec un foncteur, il faut juste plus de lignes de code à définir que le lambda C ++ 0x.for_each
?accumulate
serait plus concis (même s'il n'a pas besoin du lambda)accumulate
intérieur,for_each
mais cet exemple n'est pas utile (à des fins d'apprentissage) car il montre que nous pouvons également avoir des lambdas imbriqués :-)accumulate
. Le type du dernier argument est utilisé non seulement pour la valeur initiale, mais pour le type du résultat. Si vous y mettez unint
, il accumuleraint
s même si le vecteur afloat
. Le résultat peut être subtilement erroné, et le compilateur restituera le résultat dans un flottant sans vous le dire.for_each
-vous si vous en avezaccumulate
?La façon la plus simple est d'utiliser
std:accumuate
unvector<int> A
:la source
Prasoon a déjà proposé une multitude de façons différentes (et bonnes) de le faire, dont aucune n'a besoin d'être répétée ici. Je voudrais cependant suggérer une approche alternative pour la vitesse.
Si vous allez faire cela un peu, vous voudrez peut-être envisager de "sous-classer" votre vecteur afin qu'une somme d'éléments soit maintenue séparément (pas réellement un vecteur de sous-classification qui est incertain en raison de l'absence d'un destructeur virtuel - je parle plus d'une classe qui contient la somme et un vecteur,
has-a
plutôt queis-a
, et fournit les méthodes de type vecteur).Pour un vecteur vide, la somme est mise à zéro. À chaque insertion dans le vecteur, ajoutez l'élément inséré à la somme. À chaque suppression, soustrayez-le. Fondamentalement, tout ce qui peut changer le vecteur sous-jacent est intercepté pour garantir la cohérence de la somme.
De cette façon, vous disposez d'une méthode O (1) très efficace pour «calculer» la somme à tout moment (il suffit de renvoyer la somme actuellement calculée). L'insertion et la suppression prendront un peu plus de temps lorsque vous ajustez le total et vous devez prendre en compte ce résultat de performance.
Les vecteurs où la somme est nécessaire plus souvent que le vecteur n'est changé sont ceux susceptibles de bénéficier de ce schéma, puisque le coût de calcul de la somme est amorti sur tous les accès. Évidemment, si vous n'avez besoin que de la somme toutes les heures et que le vecteur change trois mille fois par seconde, il ne conviendra pas.
Quelque chose comme ça suffirait:
Évidemment, c'est du pseudo-code et vous voudrez peut-être avoir un peu plus de fonctionnalités, mais cela montre le concept de base.
la source
std::vector
n'est pas destiné au sous-classement.has-a
vecteur à l'intérieur, plutôt que d'être une sous-classe appropriée (is-a
).operator[](int)
, les itérateurs non const ...Pourquoi effectuer la sommation vers l'avant alors que vous pouvez la faire vers l'arrière ? Donné:
Nous pouvons utiliser l'indice, en comptant à rebours:
Nous pouvons utiliser la "souscription" vérifiée par intervalle (au cas où):
Nous pouvons utiliser des itérateurs inverses dans une boucle for:
Nous pouvons utiliser des itérateurs avant, itérant en arrière, dans une boucle for (oooh, délicat!):
Nous pouvons utiliser
accumulate
avec des itérateurs inversés:Nous pouvons utiliser
for_each
avec une expression lambda en utilisant des itérateurs inverses:Ainsi, comme vous pouvez le voir, il existe autant de façons de faire la somme du vecteur en arrière que de faire la somme du vecteur en avant, et certaines d'entre elles sont beaucoup plus intéressantes et offrent beaucoup plus de possibilités d'erreurs ponctuelles.
la source
v.size()
.la source
boost::accumulate
est juste un emballage autourstd::accumulate
.#include <numeric>
etstd::accumulate(v.begin(), v.end(), (int64_t)0);
. Notez que le type de la valeur initiale de l'accumulateur est utilisé comme type d'accumulateur, donc si vous voulez additionner des éléments 8 bits en un résultat 64 bits, c'est comme ça que vous le faites.On peut aussi utiliser
std::valarray<T>
comme çaCertains peuvent ne pas trouver cette méthode efficace car la taille de
valarray
doit être aussi grande que la taille du vecteur et l'initialisationvalarray
prendra également du temps.Dans ce cas, ne l'utilisez pas et considérez-le comme une autre façon de résumer la séquence.
la source
C ++ 0x uniquement:
Ceci est similaire au BOOST_FOREACH mentionné ailleurs et a le même avantage de clarté dans des situations plus complexes, par rapport aux foncteurs avec état utilisés avec accumulate ou for_each.
la source
for (int n : v) sum += n;
en,for (auto n : v) sum += n;
cela fonctionnera avec n'importe quel modèle vectoriel. Je savais que OP se réfère au vecteur <int>, mais cette façon est un peu plus générale :-)Je suis un utilisateur de Perl, un jeu que nous avons est de trouver toutes les différentes façons d'incrémenter une variable ... ce n'est pas vraiment différent ici. La réponse au nombre de façons de trouver la somme des éléments d'un vecteur en C ++ est probablement
an infinity
...Mes 2 cents:
En utilisant BOOST_FOREACH, pour s'affranchir de la syntaxe de l'itérateur laid:
itération sur indices (très facile à lire).
Cet autre est destructeur, accédant au vecteur comme une pile:
la source
start + length
). Les itérateurs réels doivent également être entièrement optimisés. N'oubliez pas que ce n'est pas perl; il est entièrement compilé en asm, non interprété.la source
int
pour indexer unstd::vector
n'est pas sûr en général.v.size()
peut être plus grand que la valeur la plus élevée qui peut être stockéeint
(notez qu'avec certaines plateformes et compilateurs ciblessize_of(int) < size_of(size_t)
). Dans ce cas, votre code débordera l'index. std :: vector <T> :: size_type devrait être préféré.C'est facile. C ++ 11 fournit un moyen simple de résumer les éléments d'un vecteur.
la source