¿Cómo puedo detectar la última iteración en un bucle sobre std:: map?


Estoy tratando de averiguar 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 maneras de hacer esto: iteradores de acceso aleatorio, la función distance, etc. ¿Cuál es el método canónico?

Edición: ¡no hay iteradores de acceso aleatorio para mapas!

Author: Lightness Races in Orbit, 2008-09-30

14 answers

Canónico? 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 en las cosas más simples...)

 24
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:02

Esto parece ser el más simple:

bool last_iteration = iter == (--someMap.end());
 14
Author: Torlack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 22:58:09

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 se hizo hace un tiempo, pensé que valdría la pena compartirla.

 14
Author: dutchdukes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 11:13:35

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
        }
}
 10
Author: camh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-30 11:54:13

Mark Ransom modificado para que realmente funcione como estaba previsto.

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
 6
Author: KTC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 22:57:57

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

Boost.Siguiente (y el Impulso equivalente.Anterior)

Su ejemplo se vería como:

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
    }
}
 6
Author: Pieter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 10:28:32

El siguiente código sería optimizado por un compilador para ser 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 por reglas OOP porque std:: map tiene una función miembro especial rbegin para el código como:

final_iter = someMap.end();
--final_iter;
 3
Author: mpoleg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-08 12:57:52
#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 bucle sea apretado y preciso... Tenga en cuenta 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 añadida 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.

 1
Author: paxos1977,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 01:20:31

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 (MANTENERLO SIMPLEMENTE SIMPLE)

 1
Author: Angelin Nadar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-06 05:48:13

Un enfoque simple, pero eficaz:

  size_t items_remaining = someMap.size();

  for (iter = someMap.begin(); iter != someMap.end(); iter++) {
    bool last_iteration = items_remaining-- == 1;
  }
 0
Author: Jason Etheridge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 23:01:10

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);
 0
Author: Ates Goral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 05:10:19

Qué tal esto, nadie lo menciona sino...

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

 0
Author: Todoroki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-02 10:34:30

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
 -1
Author: florin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-30 15:07:00

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

 -2
Author: Daniel Spiewak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 23:39:24