Con el nuevo bucle for basado en rangos podemos escribir código como
for(auto x: Y) {}
Qué IMO es una gran mejora de (por ejemplo)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
¿Se puede usar para recorrer dos bucles simultáneos, como la zip
función Pythons ? Para aquellos que no están familiarizados con Python, el código:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Da como salida (1,4) (2,5) (3,6)
for
solo se puede usar con una variable, por lo que no. Si quisiera acceder a dos valores a la vez, tendría que usar algo comostd::pair
zip()
función que devuelva tuplas e iterar sobre la lista de tuplas.for(;;)
puede obtener este comportamiento, aunque sea a largo plazo, por lo que la pregunta es realmente: ¿Es posible "auto" sobre dos objetos a la vez?Respuestas:
Advertencia:
boost::zip_iterator
y aboost::combine
partir de Boost 1.63.0 (26 de diciembre de 2016) causará un comportamiento indefinido si la longitud de los contenedores de entrada no es la misma (puede fallar o iterar más allá del final).A partir de Boost 1.56.0 (7 de agosto de 2014), puede usar
boost::combine
(la función existe en versiones anteriores pero no está documentada):Esto imprimiría
En versiones anteriores, usted mismo podía definir un rango como este:
El uso es el mismo.
fuente
optional
elementos para posibilidades de iteración más allá del final ...Así que escribí este zip antes cuando estaba aburrido, decidí publicarlo porque es diferente a los demás en que no usa boost y se parece más a c ++ stdlib.
Ejemplo de uso:
fuente
[](int i,int j,float k,float l)
funciona? ¿Es esta una función lambda?std::for_each
pero puede usar un número arbitrario de rangos, los parámetros en la lambda dependen de la cantidad de iteradores que le dé a la funciónPuede utilizar una solución basada en
boost::zip_iterator
. Cree una clase de contenedor falsa que mantenga referencias a sus contenedores y que regresenzip_iterator
de las funciones miembrobegin
yend
. Ahora puedes escribirImplementación de ejemplo (prueba):
Dejo la versión variadic como un excelente ejercicio para el lector.
fuente
boost::iterator_range
+boost::zip_iterator
, incluso la versión variadic.boost::zip_iterator
no funciona con rangos de diferentes longitudesstd :: transform puede hacer esto trivialmente:
Si la segunda secuencia es más corta, mi implementación parece estar dando valores inicializados predeterminados.
fuente
b
.Consulte
<redi/zip.h>
unazip
función que funcione con range-basefor
y acepte cualquier número de rangos, que pueden ser rvalues o lvalues y pueden tener diferentes longitudes (la iteración se detendrá al final del rango más corto).Huellas dactilares
0 1 2 3 4 5
fuente
boost/tuple/tuple_io.hpp
paracout << i;
boost::get<0>(i)
yboost::get<1>(i)
. No estoy seguro de por qué la muestra original no se pudo adaptar directamente, podría tener que ver con el hecho de que mi código toma referencias constantes a los contenedores.Con range-v3 :
La salida:
fuente
Me encontré con esta misma pregunta de forma independiente y no me gustó la sintaxis de ninguno de los anteriores. Entonces, tengo un archivo de encabezado corto que esencialmente hace lo mismo que boost zip_iterator pero tiene algunas macros para hacer que la sintaxis sea más aceptable para mí:
https://github.com/cshelton/zipfor
Por ejemplo, puedes hacer
El principal azúcar sintáctico es que puedo nombrar los elementos de cada contenedor. También incluyo un "mapfor" que hace lo mismo, pero para mapas (para nombrar el ".first" y ".second" del elemento).
fuente
fuente
Si le gusta la sobrecarga del operador, aquí tiene tres posibilidades. Los dos primeros utilizan
std::pair<>
ystd::tuple<>
, respectivamente, como iteradores; el tercero extiende esto al rango basadofor
. Tenga en cuenta que no a todo el mundo le gustarán estas definiciones de los operadores, por lo que es mejor mantenerlas en un espacio de nombres separado y tener unausing namespace
en las funciones (¡no en archivos!) Donde le gustaría usarlas.fuente
Para una biblioteca de procesamiento de flujo de C ++ que estoy escribiendo, estaba buscando una solución que no se base en bibliotecas de terceros y funcione con una cantidad arbitraria de contenedores. Terminé con esta solución. Es similar a la solución aceptada que usa boost (y también da como resultado un comportamiento indefinido si las longitudes del contenedor no son iguales)
fuente
operator*
forseq::iterator
devuelve unastd::tuple
de las referencias constantes.Si tiene un compilador compatible con C ++ 14 (por ejemplo, gcc5), puede usarlo
zip
proporcionado en lacppitertools
biblioteca por Ryan Haining, que parece realmente prometedor:fuente
Boost.Iterators tiene
zip_iterator
que puede usar (ejemplos en los documentos). No funcionará con range for, pero puedes usarstd::for_each
y lambda.fuente
for_each
sería menos complicado.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)); });
?Aquí hay una versión simple que no requiere impulso. No será particularmente eficiente ya que crea valores temporales y no generaliza sobre contenedores que no sean listas, pero no tiene dependencias y resuelve el caso más común de compresión.
Aunque las otras versiones son más flexibles, a menudo el objetivo de utilizar un operador de lista es hacer una simple línea. Esta versión tiene la ventaja de que el caso común es simple.
fuente