Est-il possible d'itérer un vecteur de la fin au début?
for (vector<my_class>::iterator i = my_vector.end();
i != my_vector.begin(); /* ?! */ ) {
}
Ou est-ce seulement possible avec quelque chose comme ça:
for (int i = my_vector.size() - 1; i >= 0; --i) {
}
Réponses:
Le meilleur moyen est:
rbegin()
/rend()
ont été spécialement conçus à cet effet. (Et oui, incrémenter areverse_interator
le fait reculer.)Maintenant, en théorie, votre méthode (en utilisant
begin()
/end()
&--i
) fonctionnerait,std::vector
l'itérateur étant bidirectionnel, mais rappelez-vous, ceend()
n'est pas le dernier élément - c'est un au-delà du dernier élément, donc vous devez d'abord décrémenter, et vous êtes fait lorsque vous atteignezbegin()
- mais vous devez encore effectuer votre traitement.MISE À JOUR: J'étais apparemment trop agressif en réécrivant la
for()
boucle enwhile()
boucle. (La partie importante est que le--i
est au début.)la source
--i
posera un gros problème si le conteneur est vide ... Avant de passer endo - while
boucle, il est logique de vérifier(my_vector.begin() != my_vector.end())
.do-while
boucle au lieu d'une simplewhile
boucle? Vous n'aurez alors pas besoin de contrôle spécial pour les vecteurs vides.auto
pour une meilleure lisibilité?Si vous avez C ++ 11, vous pouvez utiliser
auto
.la source
Le "modèle" bien établi pour l'itération inverse dans des plages fermées-ouvertes se présente comme suit
ou, si vous préférez,
Ce modèle est utile, par exemple, pour l'indexation inverse d'un tableau à l'aide d'un index non signé
(Les personnes qui ne sont pas familières avec ce modèle insistent souvent sur l'utilisation de types entiers signés pour l'indexation de tableaux, car elles pensent à tort que les types non signés sont en quelque sorte "inutilisables" pour l'indexation inversée)
Il peut être utilisé pour itérer sur un tableau en utilisant une technique de "pointeur glissant"
ou il peut être utilisé pour une itération inverse sur un vecteur en utilisant un itérateur ordinaire (et non inversé)
la source
--end()
end()
. Même s'ils semblent commencer àend()
, ils s'assurent toujours de décrémenter l'itérateur avant le premier accès.auto a = vector<int>{0,1,2}; bool reversed = 0; auto it = (!reversed?a.begin():a.end()); auto end = (reversed?a.begin():a.end());
while(it != end) { if(reversed)--it; cout << *it << endl; if(!reversed)++it; }
reversed
quatre fois - deux d'entre eux dans une boucle. Bien sûr, tester un booléen est très rapide, mais quand même, pourquoi travailler n'est-il pas nécessaire? Surtout, puisque le seul but semble être de rendre le code illisible. comment utiliser deux boucles séparées?if (reversed) for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it) {doStuff(*it);} else for (auto it = my_vector.begin(); it != my_vector.end(); ++it) {doStuff(*it);}
if
mais je voulais me débarrasser du modèle sur ledoStuff()
. C'est toujours faisable avec les deux queif
vous avez en faisant une boucle dans l'autre sens sur le premier.À partir de c ++ 20, vous pouvez utiliser une
std::ranges::reverse_view
et une boucle for basée sur une plage:Ou même
Malheureusement, au moment de la rédaction de cet article (janvier 2020), aucun compilateur majeur n'implémente la bibliothèque de gammes, mais vous pouvez recourir aux gammes-v3 d' Eric Niebler :
la source
rend() / rbegin()
Itérateurs utilisateur :for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)
la source
Ensuite:
Sinon, en C ++ 14, faites simplement:
En C ++ 03/11, la plupart des conteneurs standard ont également une méthode
.rbegin()
and.rend()
.Enfin, vous pouvez écrire l'adaptateur de plage
backwards
comme suit:et maintenant vous pouvez le faire:
ce que je trouve assez joli.
la source
Utilisez des itérateurs inversés et faites une boucle de
rbegin()
àrend()
la source
Voici une implémentation super simple qui permet d'utiliser le pour chaque construction et ne repose que sur la bibliothèque std C ++ 14:
Cela fonctionne avec des choses qui fournissent un rbegin () et un rend (), ainsi qu'avec des tableaux statiques.
la source
Si vous pouvez utiliser la bibliothèque Boost, il existe la gamme Boost.Range qui fournit l'
reverse
adaptateur de plage en incluant:Ensuite, en combinaison avec une boucle de plage de C ++ 11
for
, vous pouvez simplement écrire ce qui suit:Étant donné que ce code est plus bref que celui utilisant la paire d'itérateurs, il peut être plus lisible et moins sujet aux erreurs car il y a moins de détails à prêter attention.
la source
boost::adaptors::reverse
c'est très utile!J'aime l'itérateur à l'envers à la fin de Yakk - la réponse d'Adam Nevraumont, mais cela me semblait compliqué pour ce dont j'avais besoin, alors j'ai écrit ceci:
Je suis capable de prendre un itérateur normal comme celui-ci:
et changez-le en ceci pour itérer en sens inverse:
la source
utiliser ce code
la source
vec
fait référence à un vecteur vide!Comme je ne veux pas introduire de nouvelle syntaxe C ++ de type extraterrestre, et que je veux simplement construire sur des primitives existantes, les extraits ci-dessous semblent fonctionner:
la source
arr
fait référence à un vecteur vide!