More than once I’ve had to take a list of items and group them. For instance, maybe I have a flat list of key-value pairs in alternation, like this:
[key1, value1, key2, value2, key3, value3]
It could have been that they were easier to enter that way (fewer parentheses or brackets), or maybe that’s just how they come from an outside source. Nevertheless, to actually use them, it would be better to have them in tuples:
[(key1, value1), (key2, value2), (key3, value3)]
That way, I could make them into a dictionary,
urlencode them, etc.
There is an idiom for this in Python using
grouped = list(zip(*[iter(sequence)] * chunk_size))
But this is one of those cases where “idiom” is more of a synonym for “clever hack” than anything else. Don’t get me wrong: it works, and it is clever. But there’s no reasonable way that the above line could be interpreted as readably expressing the idea of grouping a list into chunks.
In case you’re curious and don’t already know how this works,
zip is going to create each chunk by calling
next() on each of a list of
chunk_size references to the same
iter object. Since they’re all references to the same object, it’s really just getting the next
chunk_size elements from the sequence. The only reason for creating a list is that the length of the list represents the chunk size.
Frankly, it reminds me of doing something like
x + x++ + x in Java, except less readable.
Of course, we could just alias this idiom to a sensible function:
def grouplen(sequence, chunk_size): return list(zip([iter(sequence)] * chunk_size))
And that would seem to solve all our woes. But given that the idiom is quite short, and the function will have to be stuck in a file somewhere in the project and imported, it’s tempting to just use the idiom instead. This is something I wish were in
itertools, as the natural opposite to