Question

J'essaie de déterminer le meilleur moyen de déterminer si je suis dans la dernière itération d'une boucle sur une carte afin de procéder de la manière suivante:

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

Il semble y avoir plusieurs façons de procéder: itérateurs à accès aléatoire, fonction distance , etc. Quelle est la méthode canonique?

Éditer: pas d'itérateurs à accès aléatoire pour les cartes!

Était-ce utile?

La solution

Canonical? Je ne peux pas prétendre cela, mais je suggérerais

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

Modifié à corriger comme suggéré par KTC . (Merci! Parfois, vous allez trop vite et vous vous trompez dans les choses les plus simples ...)

Autres conseils

Depuis C ++ 11, vous pouvez également utiliser 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
        }
    }

Bien que la question ait été posée il y a quelque temps, je pensais que cela valait la peine d'être partagé.

Cela semble être le plus simple:

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

Si vous souhaitez simplement utiliser un ForwardIterator, cela devrait fonctionner:

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

Modifié Mark Ransom afin qu'il fonctionne réellement comme prévu.

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

Surpris, personne n’en a encore parlé, mais bien sûr, boost a quelque chose;)

Boost.Next (et le équivalent Boost.Prior)

Votre exemple ressemblerait à:

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

Le code suivant serait optimisé par un compilateur afin d'être la meilleure solution pour cette tâche, tant par ses performances que par ses règles de POO:

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

C’est le meilleur code selon les règles de la POO car std :: map a une fonction membre spéciale rbegin pour le code tel que:

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'utilisation de std :: for_each garantira que la boucle est bien ajustée et précise ... Notez l'introduction de la fonction foo () qui prend un seul argument (le type doit correspondre à ce qui est contenu dans someMap). Cette approche a en plus ajouté 1 ligne. Bien sûr, si Foo est vraiment petit, vous pouvez utiliser une fonction lambda et vous débarrasser de l'appel à & Foo.

Pourquoi travailler pour trouver le fichier EOF afin de ne rien donner.

Simplement, excluez-le;

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

KISS (KEEP IT SIMPLY SIMPLE)

Une approche simple mais efficace:

  size_t items_remaining = someMap.size();

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

Voici ma prise optimisée:

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'en est-il de cela, personne ne mentionnant mais ...

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

cela semble simple, mm ...

Programme complet:

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

Ce programme donne:

 1 2 3 4 5 | last: 6

Vous pouvez simplement extraire un élément de la carte avant l'itération, puis effectuer votre "dernière itération". travaillez hors de la boucle, puis replacez l'élément dans la carte. C'est horriblement mauvais pour le code asynchrone, mais compte tenu de la gravité du reste du C ++ pour la concurrence, je ne pense pas que ce sera un problème. : -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top