Avec la nouvelle boucle for basée sur la plage, nous pouvons écrire du code comme
for(auto x: Y) {}
Quelle IMO est une énorme amélioration par rapport (par exemple)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Peut-il être utilisé pour boucler sur deux boucles simultanées, comme la zip
fonction Pythons ? Pour ceux qui ne connaissent pas Python, le code:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Donne comme sortie (1,4) (2,5) (3,6)
for
ne peut être utilisée qu'avec une seule variable, donc non. Si vous voulez accéder à deux valeurs à la fois, vous devez utiliser quelque chose commestd::pair
zip()
fonction qui renvoie des tuples et itérer sur la liste des tuples.for(;;)
est clair que ce comportement peut être obtenu, quoique de longue haleine, la question est donc vraiment la suivante: est-il possible de "auto" sur deux objets à la fois?Réponses:
Attention:
boost::zip_iterator
et àboost::combine
partir de Boost 1.63.0 (26 décembre 2016) entraînera un comportement indéfini si la longueur des conteneurs d'entrée n'est pas la même (il peut planter ou itérer au-delà de la fin).À partir de Boost 1.56.0 (7 août 2014), vous pouvez utiliser
boost::combine
(la fonction existe dans les versions antérieures mais non documentée):Cela imprimerait
Dans les versions antérieures, vous pouviez définir vous-même une plage comme ceci:
L'utilisation est la même.
la source
optional
éléments pour des possibilités d'itération au-delà de la fin ...J'ai donc écrit ce zip avant quand je m'ennuyais, j'ai décidé de le poster car il est différent des autres en ce qu'il n'utilise pas boost et ressemble plus au c ++ stdlib.
Exemple d'utilisation:
la source
[](int i,int j,float k,float l)
fonctionne? Est-ce une fonction lambda?std::for_each
mais vous pouvez utiliser un nombre arbitraire de plages, les paramètres du lambda dépendent du nombre d'itérateurs que vous donnez à la fonctionVous pouvez utiliser une solution basée sur
boost::zip_iterator
. Créez une classe de conteneur bidon en conservant les références à vos conteneurs et qui reviennentzip_iterator
des fonctions membresbegin
etend
. Maintenant tu peux écrireExemple d'implémentation (veuillez tester):
Je laisse la version variadic comme un excellent exercice au lecteur.
la source
boost::iterator_range
+boost::zip_iterator
, même la version variadique.boost::zip_iterator
ne fonctionne pas avec des plages de longueurs différentesstd :: transform peut faire cela de manière triviale:
Si la deuxième séquence est plus courte, mon implémentation semble donner des valeurs initialisées par défaut.
la source
b
.Voir
<redi/zip.h>
pour unezip
fonction qui fonctionne avec range-basefor
et accepte n'importe quel nombre de plages, qui peuvent être rvalues ou lvalues et peuvent être de différentes longueurs (l'itération s'arrêtera à la fin de la plage la plus courte).Tirages
0 1 2 3 4 5
la source
boost/tuple/tuple_io.hpp
pourcout << i;
boost::get<0>(i)
etboost::get<1>(i)
. Je ne sais pas pourquoi l'exemple d'origine n'a pas pu être adapté directement, cela pourrait être dû au fait que mon code prend des références constantes aux conteneurs.Avec range-v3 :
Le résultat:
la source
Je suis tombé sur cette même question indépendamment et je n'ai pas aimé la syntaxe de l'un des éléments ci-dessus. Donc, j'ai un court fichier d'en-tête qui fait essentiellement la même chose que le boost zip_iterator mais qui contient quelques macros pour rendre la syntaxe plus acceptable pour moi:
https://github.com/cshelton/zipfor
Par exemple, vous pouvez faire
Le sucre syntaxique principal est que je peux nommer les éléments de chaque conteneur. J'inclus également un "mapfor" qui fait de même, mais pour les maps (pour nommer le ".first" et ".second" de l'élément).
la source
la source
Si vous aimez la surcharge des opérateurs, voici trois possibilités. Les deux premiers utilisent
std::pair<>
etstd::tuple<>
, respectivement, comme itérateurs; le troisième étend cela à la gammefor
. Notez que tout le mondeusing namespace
n'aimera pas ces définitions des opérateurs, il est donc préférable de les conserver dans un espace de noms séparé et d'avoir un dans les fonctions (pas les fichiers!) Où vous souhaitez les utiliser.la source
Pour une bibliothèque de traitement de flux C ++ que j'écris, je cherchais une solution qui ne repose pas sur des bibliothèques tierces et fonctionne avec un nombre arbitraire de conteneurs. J'ai fini avec cette solution. C'est similaire à la solution acceptée qui utilise boost (et entraîne également un comportement indéfini si les longueurs de conteneur ne sont pas égales)
la source
operator*
forseq::iterator
renvoiestd::tuple
des références const.Si vous avez un compilateur compatible C ++ 14 (par exemple gcc5), vous pouvez utiliser
zip
fourni dans lacppitertools
bibliothèque par Ryan Haining, ce qui semble vraiment prometteur:la source
Boost.Iterators a que
zip_iterator
vous pouvez utiliser (exemples dans la documentation). Cela ne fonctionnera pas avec range for, mais vous pouvez utiliserstd::for_each
et un lambda.la source
for_each
serait moins compliquée.std::for_each(make_zip_iterator(make_tuple(Y1.begin(), Y2.begin())), make_zip_iterator(make_tuple(Y1.end(), Y2.end())), [](const tuple<int, int>& t){printf("%d %d\n", get<0>(t), get<1>(t)); });
?Voici une version simple qui ne nécessite pas de boost. Il ne sera pas particulièrement efficace car il crée des valeurs temporaires, et il ne se généralise pas sur des conteneurs autres que des listes, mais il n'a pas de dépendances et il résout le cas le plus courant de compression.
Bien que les autres versions soient plus flexibles, l'intérêt d'utiliser un opérateur de liste est souvent de créer une simple ligne unique. Cette version a l'avantage que le cas commun est simple.
la source