How to write this iterator?

George Sakkis gsakkis at rutgers.edu
Tue Sep 20 03:16:37 CEST 2005


<severa at sophia.dtp.fmph.uniba.sk> wrote in message
news:mailman.597.1127133504.509.python-list at python.org...
> Sorry, my description was not very good, I meant something behaving as:
>
> >>>example=Liter("abc","12345","XY")
> >>>for x in example: print x,
>
> a 1 X b 2 Y c 3 4 5
>
> or for that append() method,
>
> >>>example=Liter("abc", "12345")
> >>>for i in range(3): print example.next(),
>
> a 1 b
>
> >>>example.append("XY")
> >>>for x in example: print x,
>
> 2 c X 3 Y 4 5
>
> Hope this clarifies what I mean
>
> Best regards
> Pavol

Check the module I posted on
http://rafb.net/paste/results/CRT7bS68.html. append() makes things more
complicated -- mainly because generators don't accept attributes, so it
has to be wrapped in a class -- but the simple generator (without
append) is more manageable:

def cycleiter(*iterables):
    """Return an 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 = cycleiter("abc","12345","XY")
    >>> list(it)
    ['a', '1', 'X', 'b', '2', 'Y', 'c', '3', '4', '5']
    >>> list(it)
    []
    """
    start = 0
    iterators = map(iter, iterables)
    while iterators:
        # cycle through the existing iterators, starting from start
        for i,current in cyclefrom(enumerate(iterators), start):
            try:
                yield current.next()
            except StopIteration: # the current iterator is exhausted
                # remove it and set the cycle to restart from the next
                del iterators[i]
                start = i
                break


def cyclefrom(iterable, start=0):
    """Cycle over the elements of the iterable starting at the given
    position.

    >>> from itertools import islice
    >>> list(islice(cyclefrom('abcde', 3), 9))
    ['d', 'e', 'a', 'b', 'c', 'd', 'e', 'a', 'b']
    >>> list(islice(cyclefrom('abcde', 5), 9))
    ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd']
    """
    # chain the last part with the first one and cycle over it. Needs
    # to replicate the iterable for consuming each part
    it1,it2 = tee(iterable)
    return cycle(chain(islice(it1, start, None), islice(it2, start)))


By the way, these generators seem general enough to make it to
itertools. Actually cyclefrom can be accomodated by adding the optional
start argument to itertools.cycle. What do you think ?

George




More information about the Python-list mailing list