Domanda

Sto cercando di capire il modo migliore per determinare se sono nell'ultima iterazione di un ciclo su una mappa per fare qualcosa del genere:

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

Sembra che ci siano diversi modi per farlo: iteratori ad accesso casuale, la funzione distance , ecc. Qual è il metodo canonico?

Modifica: nessun iteratore ad accesso casuale per le mappe!

È stato utile?

Soluzione

Canonical? Non posso affermarlo, ma suggerirei

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

Modificato per correggere come suggerito da KTC . (Grazie! A volte vai troppo veloce e fai casino con le cose più semplici ...)

Altri suggerimenti

Da C ++ 11, puoi anche usare 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
        }
    }

Anche se la domanda è stata posta qualche tempo fa, ho pensato che valesse la pena condividerla.

Questo sembra il più semplice:

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

Se vuoi solo usare un ForwardIterator, questo dovrebbe funzionare:

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

Mark Ransom modificato in modo che funzioni effettivamente come previsto.

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

Sorpreso nessuno lo ha ancora menzionato, ma ovviamente la spinta ha qualcosa;)

Boost.Next (e il Boost.Prior equivalente)

Il tuo esempio sarebbe simile:

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

Il seguente codice verrebbe ottimizzato da un compilatore in modo da essere la migliore soluzione per questa attività in base alle prestazioni e alle regole OOP:

if (&*it == &*someMap.rbegin()) {
    //the last iteration
}

Questo è il miglior codice secondo le regole OOP perché std :: map ha una funzione membro speciale rbegin per il codice come:

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

L'uso di std :: for_each assicurerà che il ciclo sia stretto e preciso ... Nota l'introduzione della funzione foo () che accetta un singolo argomento (il tipo dovrebbe corrispondere a ciò che è contenuto in someMap). Questo approccio ha l'aggiunta di essere 1 riga. Naturalmente, se Foo è davvero piccolo, puoi usare una funzione lambda e sbarazzarti della chiamata a & amp; Foo.

Perché lavorare per trovare l'EOF in modo da non dargli qualcosa.

Semplicemente, escludilo;

for (iter = someMap.begin(); someMap.end() - 1; ++iter) {
    //apply to all from begin to second last element
}

BACIO (TIENI SEMPLICEMENTE SEMPLICE)

Un approccio semplice ma efficace:

  size_t items_remaining = someMap.size();

  for (iter = someMap.begin(); iter != someMap.end(); iter++) {
    bool last_iteration = items_remaining-- == 1;
  }

Ecco il mio approccio ottimizzato:

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

Che ne dici di questo, nessuno menziona ma ...

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

sembra semplice, mm ...

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

Questo programma produce:

 1 2 3 4 5 | last: 6

Puoi semplicemente estrarre un elemento dalla mappa prima dell'iterazione, quindi eseguire la tua "ultima iterazione" lavora fuori dal ciclo e poi rimetti l'elemento in sulla mappa. Questo è orribilmente negativo per il codice asincrono, ma considerando quanto il resto del C ++ sia negativo per la concorrenza, non penso che sarà un problema. : -)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top