How to write this iterator?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Guest's Avatar

    #1

    How to write this iterator?

    Given a list of iterators, I'd like to have a new one that would
    cyclically walk over the list calling the next() method of the iterators
    (removing any iterator which is exhausted). It should also support adding
    a new iterator to the list; it should be added in front of the current
    position (so that it's called only after all the others). This is what I
    was able to write with my zero python skills (self.iters is the list of
    iterators, self.i is the index of the iterator that should be used next).
    Is there a nicer/more pythonic solution, maybe using generators?


    class Liter(object):

    def __init__(self, *iters):
    self.i=0
    self.iters=[iter(x) for x in iters]

    def append(self,wha t):
    self.iters.inse rt(self.i,what)

    def __iter__(self):
    return self

    def next(self):
    while True:
    try:
    result=self.ite rs[self.i].next()
    except StopIteration:
    del self.iters[self.i]
    except IndexError:
    if len(self.iters) is 0:
    raise StopIteration
    else:
    self.i=0
    else:
    self.i+=1
    return result



  • Paul Rubin

    #2
    Re: How to write this iterator?

    Hmm, here's an approach using the .throw() operation from PEP 342.
    It's obviously untested, since that feature is not currently part of
    Python, probably incorrect, and maybe just insane. I renamed "append"
    to "insert_iterato r" since "append" usually means put something at the
    end, not in the middle.

    from itertools import cycle
    class InsertIterator( Exception): pass

    def itergen(self, *iters):
    while iters:
    try:
    for i,it in (enumerate(it) for it in cycle(iters)):
    yield it.next()
    except StopIteration:
    del iters[i]
    except InsertIterator, new_iterator:
    # maybe the i here should be i+1?
    iters = [new_iterator] + iters[i:] + iters[:i]

    Now you can say

    ig = itergen(it1,it2 ,...)
    for x in ig:
    ....

    and if you want to insert a new iterator, just say

    ig.throw(Insert Iterator, new_iterator)

    Comment

    • Paul Rubin

      #3
      Re: How to write this iterator?

      Paul Rubin <http://phr.cx@NOSPAM.i nvalid> writes:[color=blue]
      > Hmm, here's an approach using the .throw() operation from PEP 342.
      > It's obviously untested, since that feature is not currently part of
      > Python, probably incorrect, and maybe just insane.[/color]

      Pardon the unintentional "shift/reduce conflict" above. I mean that
      the code sample I posted is probably incorrect and maybe insane, not
      that the proposed throw() feature is incorrect or insane.

      Comment

      • Daniel Dittmar

        #4
        Re: How to write this iterator?

        severa@sophia.d tp.fmph.uniba.s k wrote:[color=blue]
        > Given a list of iterators, I'd like to have a new one that would
        > cyclically walk over the list calling the next() method of the iterators
        > (removing any iterator which is exhausted). It should also support adding
        > a new iterator to the list; it should be added in front of the current
        > position (so that it's called only after all the others). This is what I
        > was able to write with my zero python skills (self.iters is the list of
        > iterators, self.i is the index of the iterator that should be used next).
        > Is there a nicer/more pythonic solution, maybe using generators?[/color]

        A generator version:

        def iterconcat (collectionlist ):
        for collection in collectionlist:
        for element in collection:
        yield element

        Extending collectionlist at runtime will work only with lists and
        similar collections. And you'll need to keep a reference to it as well.
        And it would be called after all the others, which matches your
        description, but not your code.

        Daniel

        Comment

        Working...