multirember&co

attn.steven.kuo at gmail.com attn.steven.kuo at gmail.com
Wed Apr 18 14:30:30 EDT 2007


On Apr 17, 3:52 pm, bearophileH... at lycos.com wrote:


(snipped)

>
> So far I haven't succed using the coroutine Python 2.5 allows using
> the generators, and I think still that xsplitter can be done with two
> coroutines instead of two It objects. Despite Steven's code I am
> unable still to write a working code with coroutines (probably because
> I haven't understood how they work yet). This time I take a breath and
> I show my wrong code:
>
> import collections
>
> def xsplitter(iseq, pred):
>     def it(parity):
>         queue = collections.deque()
>         while True:
>             received = (yield)
>             if received is not None:
>                 queue.append(received)
>             if queue:
>                 yield queue.popleft()
>             else:
>                 try:
>                     el = iseq.next()
>                     if pred(el) == parity:
>                         yield el
>                     else:
>                         its[not parity].send(el)
>                 except StopIteration:
>                     raise
>
>     its = [it(False), it(True)]
>     return its[True], its[False]
>
> idata = iter([1, 'a', 3, 'a', 4, 5, 6, 'a'])
> it1, it2 = xsplitter(idata, lambda x: x == 'a')
>
> from itertools import izip
> for el1, el2 in izip(it1, it2):
>     print el1, el2
>
> It prints:
> None None
> None None
> a 3
> None None
> a 4
> None None
> None None
> None None
>
> Can it be fixed? Are you able to fix it for me? (If you want you can
> think of it as an exercise to understand Python coroutines :-) ).


I don't think coroutine are what's needed here.  In particular,
using 'send' will *deplete* the iterator -- the very iterator
to which one is trying to add an element.

If you don't wish to use objects, you can replace them with
a closure:

import collections

def xsplitter(iseq, pred):
    queue = [ collections.deque(), collections.deque() ]
    def it(parity):
        while True:
            if queue[parity]:
                yield queue[parity].popleft()
            else:
                try:
                    el = iseq.next()
                    if pred(el) == parity:
                        yield el
                    else:
                        queue[not parity].append(el)
                except StopIteration:
                    raise
    its = [ it(False), it(True) ]
    return its[True], its[False]


idata = iter([1, 'a', 3, 'a', 4, 5, 6, 'a'])
it1, it2 = xsplitter(idata, lambda x: x == 'a')

from itertools import izip
for el1, el2 in izip(it1, it2):
    print el1, el2


Oh, I and do like your rewrite; it's much less
repetitive and cleaner than my original version.

--
Regards,
Steven






More information about the Python-list mailing list