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 zipfunció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)

forsolo 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::pairzip()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_iteratory aboost::combinepartir 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
optionalelementos 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_eachpero 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_iteratorde las funciones miembrobeginyend. 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_iteratorno 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>unazipfunción que funcione con range-basefory 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 5fuente
boost/tuple/tuple_io.hppparacout << 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 namespaceen 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::iteratordevuelve unastd::tuplede las referencias constantes.Si tiene un compilador compatible con C ++ 14 (por ejemplo, gcc5), puede usarlo
zipproporcionado en lacppitertoolsbiblioteca por Ryan Haining, que parece realmente prometedor:fuente
Boost.Iterators tiene
zip_iteratorque puede usar (ejemplos en los documentos). No funcionará con range for, pero puedes usarstd::for_eachy lambda.fuente
for_eachserí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