Python generator that groups another iterable into groups of N
I'm looking for a function that takes an iterable i
and a size n
and yields tuples of length n
that are sequential values from i
:
x = [1,2,3,4,5,6,7,8,9,0]
[z for z in TheFunc(x,3)]
gives
[(1,2,3),(4,5,6),(7,8,9),(0)]
Does such a function exist in the standard library?
If it exists as part of the standard library, I can't seem to find it and I've run out of terms to search for. I could write my own, but I'd rather not.
Solution 1:
When you want to group an iterator in chunks of n
without padding the final group with a fill value, use iter(lambda: list(IT.islice(iterable, n)), [])
:
import itertools as IT
def grouper(n, iterable):
"""
>>> list(grouper(3, 'ABCDEFG'))
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
"""
iterable = iter(iterable)
return iter(lambda: list(IT.islice(iterable, n)), [])
seq = [1,2,3,4,5,6,7]
print(list(grouper(3, seq)))
yields
[[1, 2, 3], [4, 5, 6], [7]]
There is an explanation of how it works in the second half of this answer.
When you want to group an iterator in chunks of n
and pad the final group with a fill value, use the grouper recipe zip_longest(*[iterator]*n)
:
For example, in Python2:
>>> list(IT.izip_longest(*[iter(seq)]*3, fillvalue='x'))
[(1, 2, 3), (4, 5, 6), (7, 'x', 'x')]
In Python3, what was izip_longest
is now renamed zip_longest
:
>>> list(IT.zip_longest(*[iter(seq)]*3, fillvalue='x'))
[(1, 2, 3), (4, 5, 6), (7, 'x', 'x')]
When you want to group a sequence in chunks of n
you can use the chunks
recipe:
def chunks(seq, n):
# https://stackoverflow.com/a/312464/190597 (Ned Batchelder)
""" Yield successive n-sized chunks from seq."""
for i in xrange(0, len(seq), n):
yield seq[i:i + n]
Note that, unlike iterators in general, sequences by definition have a length (i.e. __len__
is defined).
Solution 2:
See the grouper
recipe in the docs for the itertools
package
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
(However, this is a duplicate of quite a few questions.)