Pregunta

Estoy tratando de descubrir la mejor manera de determinar si estoy en la última iteración de un bucle 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 que hay varias formas de hacerlo: iteradores de acceso aleatorio, la función distance , etc. ¿Cuál es el método canónico?

Editar: ¡no hay iteradores de acceso aleatorio para mapas!

¿Fue útil?

Solución

Canonical? No puedo afirmar 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 te equivocas con las cosas más simples ...)

Otros consejos

Desde C ++ 11, también puede 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 se hizo hace un tiempo, pensé que valdría la pena compartirla.

Esto parece ser el más simple:

bool last_iteration = iter == (--someMap.end());

Si solo desea 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
        }
}

Modificado Mark Ransom's para que realmente funcione como se esperaba.

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)

Sorprendido, nadie lo mencionó todavía, pero, por supuesto, boost tiene algo;)

Boost.Next (y el Boost.Prior equivalente)

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
    }
}

El siguiente código sería optimizado por un compilador para que sea la mejor solución para esta tarea, tanto por rendimiento como por reglas 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 miembro especial rbegin para el código como:

final_iter = someMap.end();
--final_iter;
#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 ) );
}

El uso de 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 someMap). Este enfoque tiene la adición adicional 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 & amp; 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
}

BESO (MANTÉNGALO SIMPLEMENTE SIMPLE)

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;
  }

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);

¿Qué tal esto? Nadie lo 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 ...

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

Puede extraer un elemento del mapa antes de la iteración y luego realizar su " última iteración " trabajar fuera del ciclo y luego volver a colocar el elemento en en el mapa. Esto es terriblemente malo para el código asíncrono, pero considerando lo malo que es el resto de C ++ para la concurrencia, no creo que sea un problema. :-)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top