c++ - for - instruccion if
¿Cómo puedo detectar la última iteración en un ciclo sobre std:: map? (14)
Desde C ++ 11, también puedes usar std :: next ()
for (auto iter = someMap.begin(); iter != someMap.end(); ++iter) {
// do something for all iterations
if (std::next(iter) != someMap.end()) {
// do something for all but the last iteration
}
}
Aunque la pregunta fue hecha hace un tiempo, pensé que valdría la pena compartirla.
Estoy tratando de descubrir la mejor manera de determinar si estoy en la última iteración de un ciclo sobre un mapa para hacer algo como lo siguiente:
for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
bool last_iteration;
// do something for all iterations
if (!last_iteration) {
// do something for all but the last iteration
}
}
Parece haber varias formas de hacerlo: iteradores de acceso aleatorio, la función de distance
, etc. ¿Cuál es el método canónico?
Editar: ¡no hay iteradores de acceso aleatorio para los mapas!
El siguiente código sería optimizado por un compilador para que sea la mejor solución para esta tarea según el rendimiento y las reglas de OOP:
if (&*it == &*someMap.rbegin()) {
//the last iteration
}
Este es el mejor código según las reglas de OOP porque std :: map tiene una función de miembro especial para el código como:
final_iter = someMap.end();
--final_iter;
Esto parece ser el más simple:
bool last_iteration = iter == (--someMap.end());
Modificado Mark Ransom por lo que realmente funciona según lo previsto.
finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
Puede sacar un elemento del mapa antes de la iteración, luego realizar su "última iteración" fuera del ciclo y luego volver a colocar el elemento en el mapa. Esto es terriblemente malo para el código asincrónico, pero considerando cuán malo es el resto de C ++ para la concurrencia, no creo que sea un problema. :-)
Un enfoque simple, pero efectivo:
size_t items_remaining = someMap.size();
for (iter = someMap.begin(); iter != someMap.end(); iter++) {
bool last_iteration = items_remaining-- == 1;
}
Programa completo:
#include <iostream>
#include <list>
void process(int ii)
{
std::cout << " " << ii;
}
int main(void)
{
std::list<int> ll;
ll.push_back(1);
ll.push_back(2);
ll.push_back(3);
ll.push_back(4);
ll.push_back(5);
ll.push_back(6);
std::list<int>::iterator iter = ll.begin();
if (iter != ll.end())
{
std::list<int>::iterator lastIter = iter;
++ iter;
while (iter != ll.end())
{
process(*lastIter);
lastIter = iter;
++ iter;
}
// todo: think if you need to process *lastIter
std::cout << " | last:";
process(*lastIter);
}
std::cout << std::endl;
return 0;
}
Este programa produce:
1 2 3 4 5 | last: 6
Si solo quiere usar un ForwardIterator, esto debería funcionar:
for ( i = c.begin(); i != c.end(); ) {
iterator cur = i++;
// do something, using cur
if ( i != c.end() ) {
// do something using cur for all but the last iteration
}
}
Aquí está mi toma optimizada:
iter = someMap.begin();
do {
// Note that curr = iter++ may involve up to three copy operations
curr = iter;
// Do stuff with curr
if (++iter == someMap.end()) {
// Oh, this was the last iteration
break;
}
// Do more stuff with curr
} while (true);
Sorprendido, nadie lo mencionó aún, pero por supuesto el impulso tiene algo;)
Boost.Next (y el equivalente Boost.Prior)
Su ejemplo se vería así:
for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
// do something for all iterations
if (boost::next(iter) != someMap.end()) {
// do something for all but the last iteration
}
}
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>
using namespace boost::lambda;
// call the function foo on each element but the last...
if( !someMap.empty() )
{
std::for_each( someMap.begin(), --someMap.end(), bind( &Foo, _1 ) );
}
Usar std :: for_each asegurará que el ciclo sea ajustado y preciso ... Observe la introducción de la función foo () que toma un solo argumento (el tipo debe coincidir con lo que está contenido en algún mapa). Este enfoque tiene la adición de ser 1 línea. Por supuesto, si Foo es realmente pequeño, puede usar una función lambda y deshacerse de la llamada a & Foo.
Por qué trabajar para encontrar el EOF para que no le des algo.
Simplemente, excluirlo;
for (iter = someMap.begin(); someMap.end() - 1; ++iter) {
//apply to all from begin to second last element
}
KISS (MANTENGALO SIMPLEMENTE SIMPLE)
Qué tal esto, nadie menciona pero ...
for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
// do something for all iterations
if (iter != --someMap.end()) {
// do something for all but the last iteration
}
}
esto parece simple, mm ...
¿Canónico? No puedo reclamar eso, pero sugeriría
final_iter = someMap.end();
--final_iter;
if (iter != final_iter) ...
Editado para corregir según lo sugerido por KTC . (¡Gracias! A veces vas demasiado rápido y estropeas las cosas más simples ...)