Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect the last iteration in a loop over std::map?

I'm trying to figure out the best way to determine whether I'm in the last iteration of a loop over a map in order to do something like the following:

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

There seem to be several ways of doing this: random access iterators, the distance function, etc. What's the canonical method?

Edit: no random access iterators for maps!

like image 684
cdleary Avatar asked Sep 29 '08 22:09

cdleary


11 Answers

Canonical? I can't claim that, but I'd suggest

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

Edited to correct as suggested by KTC. (Thanks! Sometimes you go too quick and mess up on the simplest things...)

like image 196
Mark Ransom Avatar answered Oct 04 '22 20:10

Mark Ransom


Since C++11, you can also use 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
        }
    }

Although the question was asked a while ago, I thought it would be worth sharing.

like image 30
dutchdukes Avatar answered Oct 04 '22 20:10

dutchdukes


This seems like the simplest:

bool last_iteration = iter == (--someMap.end());
like image 31
Torlack Avatar answered Oct 04 '22 19:10

Torlack


If you just want to use a ForwardIterator, this should work:

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
        }
}
like image 26
camh Avatar answered Oct 04 '22 20:10

camh


Modified Mark Ransom's so it actually work as intended.

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
like image 41
KTC Avatar answered Oct 04 '22 21:10

KTC


Surprised no one mentioned it yet, but of course boost has something ;)

Boost.Next (and the equivalent Boost.Prior)

Your example would look like:

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
    }
}
like image 23
Pieter Avatar answered Oct 04 '22 19:10

Pieter


The following code would be optimized by a compiler so that to be the best solution for this task by performance as well as by OOP rules:

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

This is the best code by OOP rules because std::map has got a special member function rbegin for the code like:

final_iter = someMap.end();
--final_iter;
like image 41
mpoleg Avatar answered Oct 04 '22 19:10

mpoleg


Why to work to find the EOF so that you dont give something to it.

Simply, exclude it;

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

KISS (KEEP IT SIMPLY SIMPLE)

like image 32
Angelin Nadar Avatar answered Oct 04 '22 19:10

Angelin Nadar


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

Using std::for_each will ensure that the loop is tight and accurate... Note the introduction of the function foo() which takes a single argument (the type should match what is contained in someMap). This approach has the added addition of being 1 line. Of course, if Foo is really small, you can use a lambda function and get rid of the call to &Foo.

like image 27
paxos1977 Avatar answered Oct 04 '22 21:10

paxos1977


How about this, no one mentioning but...

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

this seems simple, mm...

like image 1
Todoroki Avatar answered Oct 04 '22 19:10

Todoroki


For someone who likes C++11 range-based loop:

    for (const auto& pair : someMap) {
      if (&pair != &*someMap.rbegin()) ...
    }

Notice only reference type works here, not auto pair

like image 1
alfred Avatar answered Oct 04 '22 19:10

alfred