¿Es posible iterar un vector desde el final hasta el principio?
for (vector<my_class>::iterator i = my_vector.end();
i != my_vector.begin(); /* ?! */ ) {
}
O es que solo es posible con algo así:
for (int i = my_vector.size() - 1; i >= 0; --i) {
}
Respuestas:
La mejor forma es:
rbegin()
Fuirend()
especialmente diseñado para ese propósito. (Y sí, incrementar a loreverse_interator
mueve hacia atrás).Ahora, en teoría, su método (usando
begin()
/end()
&--i
) funcionaría,std::vector
el iterador es bidireccional, pero recuerde,end()
no es el último elemento, es uno más allá del último elemento, por lo que tendría que disminuir primero, y está terminado cuando lleguebegin()
, pero aún debe realizar el procesamiento.ACTUALIZACIÓN: Aparentemente fui demasiado agresivo al reescribir el
for()
bucle en unwhile()
bucle. (La parte importante es que--i
está al principio).fuente
--i
causará un gran problema si el contenedor está vacío ... Antes de entrar en eldo - while
ciclo, tiene sentido verificar(my_vector.begin() != my_vector.end())
.do-while
bucle en lugar de solo unwhile
bucle? Entonces no necesitaría ninguna verificación especial para los vectores vacíos.auto
para una mejor legibilidad?Si tiene C ++ 11, puede hacer uso de
auto
.fuente
El "patrón" bien establecido para la iteración inversa a través de rangos cerrados-abiertos tiene el siguiente aspecto
o, si lo prefieres,
Este patrón es útil, por ejemplo, para la indexación inversa de una matriz utilizando un índice sin signo
(Las personas no familiarizadas con este patrón menudo insiste en usar firmado entero tipos de indexación de matrices específicamente porque creen erróneamente que los tipos sin signo son de alguna manera "inservibles" para la indexación inversa)
Se puede utilizar para iterar sobre una matriz utilizando una técnica de "puntero deslizante".
o se puede usar para la iteración inversa sobre un vector utilizando un iterador ordinario (no inverso)
fuente
--end()
end()
. Aunque parecen comenzar enend()
, siempre se aseguran de disminuir el iterador antes del primer acceso.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
cuatro veces, dos de ellas dentro de un bucle. Por supuesto, probar un booleano es muy rápido, pero aún así, ¿por qué trabajar no es necesario? Especialmente, dado que el único propósito parece ser hacer que el código sea ilegible. ¿Qué tal si usamos dos bucles separados?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
, pero quería deshacerme de la plantilla en eldoStuff()
. Sin embargo, aún es factible con los dosif
s que tiene girando al revés en el primero.Comenzando con c ++ 20, puede usar un
std::ranges::reverse_view
y un bucle for basado en rango:O incluso
Desafortunadamente, en el momento de escribir este artículo (enero de 2020), ningún compilador importante implementa la biblioteca de rangos, pero puede recurrir a los rangos-v3 de Eric Niebler :
fuente
rend() / rbegin()
Iteradores de usuario :for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)
fuente
Luego:
Alternativamente en C ++ 14 simplemente haga:
En C ++ 03/11 la mayoría de contenedores estándar tienen una
.rbegin()
y.rend()
método también.Finalmente, puede escribir el adaptador de rango de la
backwards
siguiente manera:y ahora puedes hacer esto:
que creo que es bastante bonito.
fuente
Utilice iteradores inversos y recorra de
rbegin()
arend()
fuente
Aquí hay una implementación súper simple que permite el uso de para cada construcción y se basa solo en la biblioteca estándar C ++ 14:
Esto funciona con cosas que proporcionan rbegin () y rend (), así como con matrices estáticas.
fuente
Si puede usar The Boost Library, existe Boost.Range que proporciona el
reverse
adaptador de rango al incluir:Luego, en combinación con el
for
bucle de rango de C ++ 11 , puede escribir lo siguiente:Dado que este código es más breve que el que usa el par de iteradores, puede ser más legible y menos propenso a errores, ya que hay menos detalles a los que prestar atención.
fuente
boost::adaptors::reverse
es muy útil!Me gusta el iterador al revés al final de Yakk: la respuesta de Adam Nevraumont, pero parecía complicado para lo que necesitaba, así que escribí esto:
Puedo tomar un iterador normal como este:
y cámbielo a esto para iterar al revés:
fuente
usa este código
fuente
vec
refiere a un vector vacío!Como no quiero introducir una nueva sintaxis de C ++ similar a la de un alienígena, y simplemente quiero construir sobre las primitivas existentes, los siguientes fragmentos parecen funcionar:
fuente
arr
refiere a un vector vacío!