Reputation: 71424
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!
Upvotes: 30
Views: 30610
Reputation: 11
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
Upvotes: 1
Reputation: 395
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.
Upvotes: 25
Reputation: 454
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...
Upvotes: 1
Reputation: 9300
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)
Upvotes: 3
Reputation: 39
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;
Upvotes: 3
Reputation: 17705
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
}
}
Upvotes: 6
Reputation: 158274
#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.
Upvotes: 1
Reputation: 140052
Here's my optimized take:
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);
Upvotes: -1
Reputation: 308120
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...)
Upvotes: 28
Reputation: 14326
Full program:
#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;
}
This program yields:
1 2 3 4 5 | last: 6
Upvotes: -1
Reputation: 42438
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
}
}
Upvotes: 10
Reputation: 55113
You can just pull an element out of the map prior to iteration, then perform your "last iteration" work out of the loop and then put the element back into the map. This is horribly bad for asynchronous code, but considering how bad the rest of C++ is for concurrency, I don't think it'll be an issue. :-)
Upvotes: -2
Reputation: 6917
A simple, yet effective, approach:
size_t items_remaining = someMap.size();
for (iter = someMap.begin(); iter != someMap.end(); iter++) {
bool last_iteration = items_remaining-- == 1;
}
Upvotes: 0
Reputation: 4475
This seems like the simplest:
bool last_iteration = iter == (--someMap.end());
Upvotes: 14
Reputation: 9003
Modified Mark Ransom's so it actually work as intended.
finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
Upvotes: 6