How to write this iterator?

George Sakkis gsakkis at rutgers.edu
Tue Sep 20 12:25:08 EDT 2005


"Jordan Rastrick" <jrastrick at student.usyd.edu.au> wrote:

> I've written this kind of iterator before, using collections.deque,
> which personally I find a little more elegant than the list based
> approach:

Nice, that's *much* more elegant and simple ! Here's the class-based version with append; note that
interleave is modified to put back the popped iterator before yield, otherwise append doesn't work
properly:

from collections import deque

class Interleave(object):
    """Iterator that cycles over one or more iterables, yielding one item from
    each iterable at a time. Once an iterable is exhausted, it is removed from
    the cycle. This iterator is exhausted when all participating iterables are
    exhausted.

    >>> it = Interleave("abc","12345","XY")
    >>> list(it)
    ['a', '1', 'X', 'b', '2', 'Y', 'c', '3', '4', '5']
    >>> list(it)
    []
    """

    def __init__(self, *iterables):
        iters = self.__iters = deque(map(iter, iterables))
        def generator():
            while iters:
                it = iters.popleft()
                try:
                    next = it.next()
                except StopIteration:
                    continue
                else:
                    iters.append(it)
                    yield next
        self.__this_iter = generator()

    def append(self,iterable):
        """Adds an iterable to the existing cycle of iterables.

        The given iterable is added in front of the current position in the
        cycle so that it's called only after all the others.

        >>> example = Interleave("abc", "12345")
        >>> [example.next() for i in range(3)]
        ['a', '1', 'b']
        >>> example.append("XY")
        >>> list(example)
        ['2', 'c', 'X', '3', 'Y', '4', '5']
        """
        self.__iters.append(iter(iterable))

    def __iter__(self):
        return self

    def next(self):
        return self.__this_iter.next()


if __name__ == '__main__':
    import doctest
    doctest.testmod()





More information about the Python-list mailing list