[New-bugs-announce] [issue32099] Use range in itertools roundrobin recipe

Terry J. Reedy report at bugs.python.org
Mon Nov 20 19:54:27 EST 2017


New submission from Terry J. Reedy <tjreedy at udel.edu>:

The itertools roundrobin recipe has an outer loop executed a preset number of times.  It is currently implemented with two assignments and a while loop.
https://docs.python.org/3/library/itertools.html#itertools-recipes
These can be replaced with a for loop using a reversed range.

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    nexts = cycle(iter(it).__next__ for it in iterables)
    for current_len in reversed(range(1, len(iterables)+1)):
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            nexts = cycle(islice(nexts, current_len - 1))

I think this is easier to understand.  So do some other participants in the current python-ideas thread 'Rewriting the "roundrobin" recipe in the itertools documentation'.

I changed 'pending' to 'current_len' because, to me, 'pending' should be the set of iter_nexts and not their number.

I originally avoided the '-1' in the islice call by decrementing both range arguments by 1 and calling the loop variable 'reduced_len'.  But having the loop variable be the size of the nexts iterable in the next outer iteration seemed confusing and not worth the trivial efficiency gain.

An independent change would be to replace 'next' with 'iter' on the basis that reusing the builtin name is not good and because 'nexts' is awkward to pronounce.

I will produce a PR if any version is preferred to the current one.
---

The OP proposed, and some participants like, an accept-reject algorithm based on zip_longest.

def roundrobin(*iters):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Perhaps "flat_zip_nofill" is a better name, or something similar
    sentinel = object()
    for tup in it.zip_longest(*iters, fillvalue=sentinel):
        yield from (x for x in tup if x is not sentinel)

I dislike creating tuples we don't want, with values we don't want, with an arbitrarily small acceptance ratio.  I also note that zip_longest is properly used in grouper, whereas roundrobin is the only recipe using cycle.

----------
assignee: docs at python
components: Documentation
messages: 306605
nosy: docs at python, rhettinger, terry.reedy
priority: normal
severity: normal
stage: needs patch
status: open
title: Use range in itertools roundrobin recipe
type: enhancement
versions: Python 3.7

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue32099>
_______________________________________


More information about the New-bugs-announce mailing list