tags:

views:

360

answers:

8

If i iterate over a STL container i sometimes need to know if the current item is the last one in the sequence. Is there a better way, then doing something like this? Can i somehow convert rbegin()?

std::vector<int> myList;

// ....
std::vector<int>::iterator lastit = myList.end();  
lastit--;

for(std::vector<int>::iterator it = myList.begin(); it != myList.end(); it++)  {
     if(it == lastit)
     {
        // Do something with last element
     }
     else
     {
       //  Do something with all other elements
     }
+2  A: 

Maybe you can iterate backwards (use rbegin/rend) and put your special task before the loop or replace the end check with it != lastit and put the special handling after the loop

Ulrich Gerhardt
+3  A: 

Try the following

std::vector<int>::iterator it2 = (++it);
if ( it2 == myList.end() ) {
  ...
}

The following should work as well

if ( it+1 == myList.end() ) {
  // it is last
  ...
}
JaredPar
Or: if (boost::next(it) == lastit) { ...
Pukku
A: 

If you're using a vector, it's actually much simpler to use an integer index to iterate:

std::vector<int> myList;
for (unsigned int i = 0; i < myList.size(); i++)
{
  if (i == (myList.size() - 1))
  {
    processDifferently (myList[i])
  }
  else
  {
    process (myList[i])
  }
}

Minimizing the number of calls to myList.size() is left as an exercise for the OP :)

Alexis Bietti
+1  A: 

I would have some doubts about my design if some elements need to be treated differntly, but this suggestion is a bit cleaner for me (don't forget to test for empty containers)

std::vector<int>::iterator lastit = myList.end();
if (lastit != myList.begin())
{
  lastit--;
  for(std::vector<int>::iterator it = myList.begin(); it != lastit; ++it)
  {
     // Do
  }
  // Do with last
}
stefaanv
I don't think this needs to be bad design. How about producing output like "a, b, c and d"?
Ulrich Gerhardt
A: 

For a random access iterator like that for vector, you don't need the temporarary. You can say:

if ( it + 1 == v.end() ) {
   // at one before end
}

Edit: And even for non-random access types one could use std:;distance:

if ( distance( it, v.end() ) == 1 ) {
   // at one before end
}
anon
+1  A: 

Use reversed iteration, this way you will have only one end()-1-like computation (notice the rbegin()+1) and no comparsions:

for(vector<int>::iterator it = myValues.rbegin()+1; it != myValues.rend(); it++) {
    cout << *it << endl;
}
cout << "Process last one: " << *myValues.rbegin() << endl;

Also, for the vector<>, computing end()-1 is probably fast, so you can also do it like following:

for(vector<int>::iterator it = myValues.begin(); it != myValues.end()-1; it++) {
    cout << *it << endl;
}
cout << "Process last one: " << *myValues.rbegin() << endl;

If you don't want to process the element after the loop, you can:

for(vector<int>::iterator it = myValues.rbegin(); it != myValues.rend(); it++) {
    if(it == myValues.rbegin())
        cout << "Process last one: " << *it << endl;
    else
        cout << *it << endl;
}
Usually the order is important, so processing in reverse order isn't practical.
Mark Ransom
I mostly find my self traversing collections in "for_each" like way, i.e. to do something with each element, without referring to other elements and order of processing.
True, for_each style processing wouldn't care about the order. But if you care about which one is the last, you probably care about the order of the others as well.
Mark Ransom
+1  A: 

Duplicate: See http://stackoverflow.com/questions/151046/c-last-loop-iteration-stl-map-iterator

Mark Ransom
It is weird that nobody proposed reversed iteration, where skipping first (that is: last) element is very simple.. Like in my answer here.
A: 

An important question is: why create a loop if you do something special for 1 element. Why not do something special to the 3rd element? To every 4rth? ...

Just iterate over the elements to be treated the same, write separate code to treat the others.

Have a look at answers to this question, too.

xtofl