<div dir="ltr">After correcting Terry's off-by-one error, I get this on Python 3.6 (and bumping NUMBER to 1000). In speed, Terry's is either very slightly faster or very slightly slower than the recipe, depending on the data. I think Terry's is more readable that roundrobin(), but still requires a little thought compared to Bunslow's. However, using the builtin name 'next' as a variable name seems like a bad choice to me (it doesn't break in this code, but seems like bad practice, i'd choose some other variable name).<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><font face="monospace, monospace">507-code % python rr_tester.py</font></div></div><div><div><font face="monospace, monospace">testing with equal_data</font></div></div><div><div><font face="monospace, monospace"> roundrobin 0.187816</font></div></div><div><div><font face="monospace, monospace"> bunslow 0.393162</font></div></div><div><div><font face="monospace, monospace"> terry 0.183851</font></div></div><div><div><font face="monospace, monospace"> stackoverflow 0.675543</font></div></div><div><div><font face="monospace, monospace">**************************************************</font></div></div><div><div><font face="monospace, monospace">testing with unequal_data</font></div></div><div><div><font face="monospace, monospace"> roundrobin 0.209959</font></div></div><div><div><font face="monospace, monospace"> bunslow 0.555731</font></div></div><div><div><font face="monospace, monospace"> terry 0.233015</font></div></div><div><div><font face="monospace, monospace"> stackoverflow 0.746880</font></div></div><div><div><font face="monospace, monospace">**************************************************</font></div></div><div><div><font face="monospace, monospace">testing with extreme_data</font></div></div><div><div><font face="monospace, monospace"> roundrobin 0.053149</font></div></div><div><div><font face="monospace, monospace"> bunslow 0.273607</font></div></div><div><div><font face="monospace, monospace"> terry 0.051963</font></div></div><div><div><font face="monospace, monospace"> stackoverflow 0.158515</font></div></div><div><font face="monospace, monospace"><br></font></div><div><div><font face="monospace, monospace">508-code % python --version</font></div></div><div><div><font face="monospace, monospace">Python 3.6.2 :: Anaconda custom (x86_64)</font></div></div></blockquote></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 20, 2017 at 9:15 AM, Terry Reedy <span dir="ltr"><<a href="mailto:tjreedy@udel.edu" target="_blank">tjreedy@udel.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 11/20/2017 11:08 AM, Steven D'Aprano wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Please don't make claims about correctness and efficiency without<br>
testing the code first. The second suggestion given there, using deque,<br>
is *not* correct as provided, as it fails to work with iterables. It<br>
requires the caller to pass only iterators, unlike the existing<br>
roundrobin recipe which accepts any iterable.<br>
<br>
Nor is it more efficient, at least on my machine -- in fact the<br>
opposite, it is the worst performing of the four recipes I've tried:<br>
<br>
- the current recipe from the itertools docs;<br>
- your re-write, using zip_longest;<br>
- Terry's version;<br>
- and the one from stackoverflow.<br>
<br>
I've attached my test code, in case you want to play around with it.<br>
Apologies in advance for any bugs in the test code (its 2 in the<br>
morning here and I've had a long day).<br>
<br>
According to my testing, on my computer using Python 3.5, Terry's code<br>
is by far the fastest in all three separate test cases, but that<br>
probably shouldn't count since it's buggy (it truncates the results and<br>
bails out early under some circumstances). Out of the implementations<br>
that don't truncate, the existing recipe is by far the fastest.<br>
<br>
Terry, if you're reading this, try:<br>
<br>
list(roundrobin('A', 'B', 'CDE'))<br>
</blockquote>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Your version truncates the results to A B C instead of A B C D E as the<br>
itertools recipe gives.<br>
</blockquote>
<br></span>
This is due to an off-by-1 error which I corrected 3 hours later in a follow-up post, repeated below.<br>
---<br>
<br>
Correct off-by-one error. I should have tested with an edge case such as<br>
print(list(roundrobin('ABC', '')))<br>
<br>
> The following combines 3 statements into one for statement.<br>
><br>
> def roundrobin(*iterables):<span class=""><br>
> "roundrobin('ABC', 'D', 'EF') --> A D E B F C"<br></span>
> nexts = cycle(iter(it).__next__ for it in iterables)<br>
> for reduced_len in reversed(range(1, len(iterables))):<br>
<br>
Make that 0 rather than 1 for start value.<br>
<br>
> try:<br>
> for next in nexts:<br>
> yield next()<br>
> except StopIteration:<br>
> nexts = cycle(islice(nexts, reduced_len))<br>
<br>
A slightly clearer, slightly less efficient alternative would be<br>
<br>
def roundrobin(*iterables):<span class=""><br>
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"<br></span>
nexts = cycle(iter(it).__next__ for it in iterables)<br>
for current_len in reversed(range(1, len(iterables)+1)):<br>
try:<br>
for next in nexts:<br>
yield next()<br>
except StopIteration:<br>
nexts = cycle(islice(nexts, current_len - 1))<span class="HOEnZb"><font color="#888888"><br>
<br>
-- <br>
Terry Jan Reedy</font></span><div class="HOEnZb"><div class="h5"><br>
<br>
______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a><br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Keeping medicines from the bloodstreams of the sick; food <br>from the bellies of the hungry; books from the hands of the <br>uneducated; technology from the underdeveloped; and putting <br>advocates of freedom in prisons. Intellectual property is<br>to the 21st century what the slave trade was to the 16th.<br></div>
</div>