Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.mixmin.net!news.musoftware.de!wum.musoftware.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Neil Cerutti Newsgroups: comp.lang.python Subject: zip_longest_by Date: 17 Oct 2012 16:00:03 GMT Organization: Norwich University Lines: 43 Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Trace: individual.net deXlSHBpthTD+PkhfAPMXwWHfL14gyH/S5ea84bDtEdHM5UX2IhrbLqDSkY7bbszzu Cancel-Lock: sha1:cp7VRh2g73988w58ioiHNR/jO4A= User-Agent: slrn/0.9.9p1/mm/ao (Win32) Xref: csiph.com comp.lang.python:31522 While working through Project Euler, a fun source of exercises, I composed the following iterator recipe to yield from multiple iterators in fixed-length groups: import itertools def zip_longest_by(*args, fillvalue=None, n=1, grouper=tuple): """Yield n at a time from each of the args, with padding. It terminates when the longest iterator is exhausted. >>> for i, j in zip_longest_by("ABCDEFGH", "HIJKL", ... fillvalue="-", n=3, grouper=''.join): ... print(i, j) ABC HIJ DEF KL- GH- --- >>> for n1, n2 in zip_longest_by(reversed('1234'), reversed('678'), ... fillvalue='0', n=3, grouper=lambda a: ''.join(reversed(a))): ... print(n1, n2) 234 678 001 000 """ it = itertools.zip_longest(*args, fillvalue=fillvalue) while True: accum = list() try: for i in range(n): accum += zip(*next(it)) except StopIteration: for i in range(n - i): accum.append(tuple(itertools.repeat(fillvalue, len(args)))) yield tuple(grouper(item) for item in zip(*accum)) break yield tuple(grouper(item) for item in zip(*accum)) The interface could stand improvement. I find the grouper argument very convenient, but none of the other grouping iterators find it needful. Forcing n to be a keyword argument is unfortunate as well. -- Neil Cerutti