How to write this iterator?

G

Guest

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,what):
self.iters.insert(self.i,what)

def __iter__(self):
return self

def next(self):
while True:
try:
result=self.iters[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
 
P

Paul Rubin

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_iterator" 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
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(InsertIterator, new_iterator)
 
P

Paul Rubin

Paul Rubin said:
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.

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.
 
D

Daniel Dittmar

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?

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top