Skip to content

Instantly share code, notes, and snippets.

@kouk
Created November 11, 2016 15:13
Show Gist options
  • Save kouk/5f0b192eaba8901f5680d8c3a46eefb8 to your computer and use it in GitHub Desktop.
Save kouk/5f0b192eaba8901f5680d8c3a46eefb8 to your computer and use it in GitHub Desktop.
Consume an iterable in chunks, skipping what's not needed. Similar to the "grouper" recipe in https://docs.python.org/2/library/itertools.html#recipes
from itertools import islice
from igrouper import igrouper
test = []
for batch in list(igrouper(range(24), 5)):
test.append(list(batch))
assert test == [[], [], [], [], []]
test = []
for batch in igrouper(range(24), 5):
test.append(list(batch))
assert test == [[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23]]
test = []
for batch in igrouper(range(24), 5, True):
test.append(list(batch))
assert test == [[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, None]]
test = []
for batch in igrouper(range(24), 5):
test.append(list(islice(batch, 0, 1)))
assert test == [[0],
[5],
[10],
[15],
[20]]
test = []
for batch in igrouper(range(24), 5):
test.append(list(islice(batch, 2, 4)))
assert test == [[2, 3],
[7, 8],
[12, 13],
[17, 18],
[22, 23]]
test = []
for batch in igrouper(range(24), 5):
test.append(list(islice(batch, 0, None, 2)))
assert test == [[0, 2, 4],
[5, 7, 9],
[10, 12, 14],
[15, 17, 19],
[20, 22]]
test = []
for batch in igrouper(range(24), 5, True):
test.append(list(islice(batch, 0, None, 2)))
assert test == [[0, 2, 4],
[5, 7, 9],
[10, 12, 14],
[15, 17, 19],
[20, 22, None]]
from itertools import imap
def igrouper(iterable, n, fill=False, fillval=None):
"""Consume an iterable in chunks of size n.
Consume an iterable in chunks of size n, just like the
well-known recipe with `izip` except return generators instead.
For example:
for batch in igrouper(range(24), 5):
print list(batch)
Will output:
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23]
If `fill` is True then the last chunk will be filled with `fillval`
up to size `n`, i.e. for the previous example it could be:
[20, 21, 22, 23, None]
"""
done = []
def chunk(it):
for i in it:
yield i
done.append(it)
if fill is True:
yield fillval
iterables = [iter(iterable)] * n
iterators = map(chunk, iterables)
while not done:
chunk = imap(next, iterators)
yield chunk
# consume the rest of the chunk before going to the next
for _ in chunk:
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment