C ++ 11 proporciona varias formas de iterar sobre contenedores. Por ejemplo:
Bucle basado en rango
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
Sin embargo, ¿cuál es la forma recomendada de iterar sobre dos (o más) contenedores del mismo tamaño para lograr algo como:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
memecs
fuente
fuente
transform
presente en#include <algorithm>
?containerA = containerB;
lugar del ciclo.Respuestas:
Bastante tarde para la fiesta. Pero: iteraría sobre índices. Pero no con el
for
ciclo clásico, sino con unfor
ciclo basado en rangos sobre los índices:indices
es una función contenedora simple que devuelve un rango (evaluado con pereza) para los índices. Dado que la implementación, aunque simple, es demasiado larga para publicarla aquí, puede encontrar una implementación en GitHub .Este código es tan eficiente como usar un
for
bucle clásico manual .Si este patrón ocurre con frecuencia en sus datos, considere usar otro patrón que tenga
zip
dos secuencias y produzca un rango de tuplas, correspondientes a los elementos emparejados:La implementación de
zip
se deja como un ejercicio para el lector, pero se deriva fácilmente de la implementación deindices
.(Antes de C ++ 17, tendría que escribir lo siguiente :)
fuente
boost::counting_range(size_t(0), containerA.size())
indices
implementación produce un resultado del compilador que es idéntico al uso defor
bucles manuales . No hay gastos generales de ningún tipo.Para su ejemplo específico, solo use
Para el caso más general, puede usar Boost.Iterator's
zip_iterator
, con una pequeña función para hacerlo utilizable en bucles for basados en rangos. En la mayoría de los casos, esto funcionará:Ejemplo vivo.
Sin embargo, para la generalidad en toda regla, es probable que desee algo más parecido a este , que funcionará correctamente para las matrices y tipos definidos por el usuario que no tienen miembros
begin()
/end()
pero no tienenbegin
/end
funciones en su espacio de nombres. Además, esto permitirá al usuario obtenerconst
acceso específicamente a través de laszip_c...
funciones.Y si eres un defensor de los mensajes de error agradables, como yo, entonces probablemente quieras esto , que verifica si se pasaron contenedores temporales a alguna de las
zip_...
funciones e imprime un mensaje de error agradable si es así.fuente
auto
funciona exactamente igual que un parámetro de plantilla, yT&&
en una plantilla es una referencia universal como se explica en el primer enlace, porauto&& v = 42
lo que se deducirá comoint&&
yauto&& w = v;
luego se deducirá comoint&
. Le permite hacer coincidir lvalues así como rvalues y dejar que ambos sean mutables, sin hacer una copia.zip_range
.me pregunto por qué nadie mencionó esto:
PD: si los tamaños del contenedor no coinciden, entonces tendrá que poner el código dentro de las declaraciones if.
fuente
Hay muchas formas de hacer cosas específicas con varios contenedores, como se indica en el
algorithm
encabezado. Por ejemplo, en el ejemplo que ha dado, podría usar enstd::copy
lugar de un bucle for explícito.Por otro lado, no hay ninguna forma incorporada de iterar genéricamente varios contenedores que no sea un bucle for normal. Esto no es sorprendente porque hay muchas formas de iterar. Piense en ello: podría iterar a través de un contenedor con un paso, un contenedor con otro paso; o a través de un recipiente hasta que llegue al final y luego comience a insertar mientras pasa hasta el final del otro recipiente; o un paso del primer recipiente por cada vez que pasa completamente por el otro recipiente y luego comienza de nuevo; o algún otro patrón; o más de dos contenedores a la vez; etc ...
Sin embargo, si quisiera crear su propia función de estilo "for_each" que recorra en iteración dos contenedores solo hasta la longitud del más corto, puede hacer algo como esto:
Obviamente puedes realizar cualquier tipo de estrategia de iteraciones que desees de forma similar.
Por supuesto, podría argumentar que simplemente hacer el bucle for interno directamente es más fácil que escribir una función personalizada como esta ... y tendría razón, si solo lo va a hacer una o dos veces. Pero lo bueno es que es muy reutilizable. =)
fuente
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
pero el compilador grita. ¿Alguien puede explicar por qué esto no es válido?for (int x = 0, y = 0; ...
funciona, perofor (int x = 0, double y = 0; ...)
no.typename...
En caso de que necesite iterar simultáneamente sobre 2 contenedores solamente, existe una versión extendida del algoritmo estándar for_each en la biblioteca de rango de impulso, por ejemplo:
Cuando necesita manejar más de 2 contenedores en un algoritmo, entonces necesita jugar con zip.
fuente
otra solución podría ser capturar una referencia del iterador del otro contenedor en una lambda y usar el operador de incremento posterior en eso. por ejemplo, una copia simple sería:
dentro de lambda puede hacer lo que sea
ita
y luego incrementarlo. Esto se extiende fácilmente al caso de múltiples contenedores.fuente
Una biblioteca de rango proporciona esta y otras funciones muy útiles. El siguiente ejemplo usa Boost.Range . El rangev3 de Eric Niebler debería ser una buena alternativa.
C ++ 17 hará que esto sea aún mejor con enlaces estructurados:
fuente
delme.cxx:15:25: error: no match for 'operator=' (operand types are 'std::tuple<int&, char&>' and 'const boost::tuples::cons<const int&, boost::tuples::cons<const char&, boost::tuples::null_type> >') std::tie(ti,tc) = i;
^19.13.26132.0
y la versión de Windows SDK10.0.16299.0
):error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const boost::tuples::cons<const char &,boost::fusion::detail::build_tuple_cons<boost::fusion::single_view_iterator<Sequence,boost::mpl::int_<1>>,Last,true>::type>' (or there is no acceptable conversion)
boost::combine
: stackoverflow.com/q/55585723/8414561También llego un poco tarde; pero puedes usar esto (función variadic estilo C):
o esto (usando un paquete de parámetros de función):
o esto (usando una lista de inicializadores entre llaves):
o puede unir vectores como aquí: ¿Cuál es la mejor manera de concatenar dos vectores? y luego iterar sobre el vector grande.
fuente
Aquí hay una variante
Uso de ejemplo
fuente