Has Next in Python Iterators

Ian ian.g.kelly at gmail.com
Mon Oct 25 19:54:42 CEST 2010


On Oct 25, 4:33 am, Kelson Zawack <zawack... at gis.a-star.edu.sg> wrote:
> The example I have in mind is list like [2,2,2,2,2,2,1,3,3,3,3] where
> you want to loop until you see not a 2 and then you want to loop until
> you see not a 3.  In this situation you cannot use a for loop as
> follows:
>
> foo_list_iter = iter([2,2,2,2,2,2,1,3,3,3,3])
> for foo_item in foo_list_iter:
>     if foo_item != 2:
>         break
> because it will eat the 1 and not allow the second loop to find it.
> takeWhile and dropWhile have the same problem.  It is possible to use
> a while loop as follows:
>
> foo_list_item = foo_list_iter.next()
> while foo_list_item == 2:
>     foo_list_item = foo_list_iter.next()
> while foo_list_item == 3:
>     foo_list_item = foo_list_iter.next()
>
> but if you can't be sure the list is not empty/all 2s then all 3s you
> need to surround this code in a try block.  Unless there is a good
> reason for having to do this I think it is undesirable because it
> means that the second clause of the loop invariant, namely that you
> are not off the end of the list, is being controlled outside of the
> loop.

from itertools import chain, imap, izip, tee
from operator import itemgetter

foo_list_iter, next_foo_list_iter = tee([2,2,2,2,2,2,1,3,3,3,3])
next_foo_list_iter = chain([None], next_foo_list_iter)
foo_list_iter = imap(itemgetter(0), izip(foo_list_iter,
next_foo_list_iter))

for foo_item in foo_list_iter:
    if foo_item != 2:
        foo_list_iter = next_foo_list_iter
        break

But in practice I think the best solution is to create an explicit
iterator wrapper that implements hasnext() and use it as needed, as
others in this thread have suggested.

Cheers,
Ian



More information about the Python-list mailing list