views:

829

answers:

4

I'd like to compare two consecutive elements in a std::list while iterating through the list. What is the proper way to access element i+1 while my iterator is at element i? Thanks Cobe

+9  A: 

Boost has a utility called next (and its inverse, prior) for just that purpose.

*itr == *next(itr)

Edit: But, if we step back to look at the forest, the real question is, why custom-write your adjacent_find function? (I recommend Nicola Bonelli's answer to be accepted.) That's part of the STL, and doesn't require using Boost, if your code doesn't use Boost (thanks to the commenters for pointing this out).

Chris Jester-Young
It's fun how almost every C++ question on the site has completely different "if you have Boost" and "if you limit to standard C++" answers. Almost as if they're different languages...
Steve Jessop
I've been thinking the same thing :)
warren
It _is_ like different languages! Boost is what makes C++ worth using, to me. :-P Not using Boost is like not using SRFIs when writing Scheme code. :-P
Chris Jester-Young
+8  A: 

The simplest way would be to hold two iterators (since you'll have to stop at the penultimate one anyway).

std::list<int>::const_iterator second = list.begin(),
                               end = list.end();

if ( second != end ) // Treat empty list
    for(std::list<int>::const_iterator first = second++; // Post-increment 
        second != end; 
        ++first, ++second)
    {
        //...
    }

Note that first is initialized with the post-incrementation of second so when the loop starts first is list.begin() and second is list.begin()+1.

Chris Jester-Young points out that boost has next and prior functions, although I am not familiar with these functions (for my sins) implementing them is trivial (especially considering that list has bidirectional iterators).

template <class Iterator>
Iterator next(Iterator i) // Call by value, original is not changed
{ 
    return ++i;
}
// Implementing prior is left as an exercise to the reader ;o)

My feeling is that use of next does not suite this problem as well as maintaining both iterators since you have to remember to make sure next(i) does not equal end() at every use.


Edits:

  • Fixed bug if the list is empty thanks to Luc Touraille's comment.
  • Add reference to next and why I think it doesn't fit this use-case.
Motti
Oops after writing the implementation of next I see that it's exactly the same as that in the link Chris included in hi post.
Motti
Ahh, the power of simple, obvious solutions! :-P I still think adjacent_find is the simplest solution of the lot, but yes.
Chris Jester-Young
+6  A: 

STL provide the adjancent_find() algorithm that can be used to find two consecutive equal elements. There is also a version with a custom predicate.

These are the prototypes:

template <class ForwardIterator>
   ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last );

template <class ForwardIterator, class BinaryPredicate>
   ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last,
                                   BinaryPredicate pred );
Nicola Bonelli
Yours is the answer I wished I wrote myself; I hope the OP accepts your answer. Good stuff! +1 (well I would +5, but the site doesn't allow that)
Chris Jester-Young
+1  A: 

List is a Reversible Container, so its iterators are Bidirectional Iterators, which is a model of Forward Iterator, which I'm pretty sure means you can do this (or something equivalent, if you're allergic to breaking out of the middle of a loop etc.):

if (!l.empty()) {
    for (list<T>::const_iterator i = l.begin();;) {
        const T &a = *i;
        ++i;
        if (i == l.end()) break;
        do_comparison(a, *i);
    }
}

You couldn't do that with an Input Iterator, because with those the values only "exist" as long as you have an iterator at them. But you can with a Forward Iterator.

Steve Jessop