How to chunk a list in Python 3?
Question:
I found the following code that is compatible with python2
from itertools import izip_longest
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
However, this isn’t working with Python 3. I get the following error
ImportError: cannot import name izip_longest
Can someone help?
I’d like to convert my list of [1,2,3,4,5,6,7,8,9]
to [[1,2,3],[4,5,6],[7,8,9]]
Edit
Now Python3 compatible
Code below is adapted from the selected answer. Simply change name from izip_longest
to zip_longest
.
from itertools import zip_longest
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
Answers:
In Python 3’s itertools
there is a function called zip_longest
. It should do the same as izip_longest
from Python 2.
Why the change in name? You might also notice that itertools.izip
is now gone in Python 3 – that’s because in Python 3, the zip
built-in function now returns an iterator, whereas in Python 2 it returns a list. Since there’s no need for the izip
function, it also makes sense to rename the _longest
variant for consistency.
According to the doc:
>>> s = [1,2,3,4,5,6,7,8,9]
>>> n = 3
>>> list(zip(*[iter(s)]*n))
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
After all that discussion above, here’s a python3 solution that I believe gives safer, more predicable results.
def chunker(iter, size):
chunks = [];
if size < 1:
raise ValueError('Chunk size must be greater than 0.')
for i in range(0, len(iter), size):
chunks.append(iter[i:(i+size)])
return chunks
example = [1,2,3,4,5,6,7,8,9]
print(' 1: ' + str(chunker(example, 1)))
print(' 3: ' + str(chunker(example, 3)))
print(' 4: ' + str(chunker(example, 4)))
print(' 8: ' + str(chunker(example, 8)))
print(' 9: ' + str(chunker(example, 9)))
print('10: ' + str(chunker(example, 10)))
The results are:
$ python3 iter_chunk.py
1: [[1], [2], [3], [4], [5], [6], [7], [8], [9]]
3: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
4: [[1, 2, 3, 4], [5, 6, 7, 8], [9]]
8: [[1, 2, 3, 4, 5, 6, 7, 8], [9]]
9: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
10: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
The source code of the grouper()
function included in the question is copied from the documentation for itertools
, more specifically the section Itertools Recipes.
In this documentation, it is stated that:
This section shows recipes for creating an extended toolset using the existing itertools
as building blocks.
Substantially all of these recipes and many, many others can be installed from the more-itertools
project found on the Python Package Index:
pip install more-itertools
If you look at the documentation of the more-itertools
package, then you will notice that the objective pursued in the question, i.e. to chunk a list, could be achieved with the following functions present in this package:
sliced()
to yield a list from sliceable iterables,
chunked()
to yield a list from non-sliceable iterables.
ichunked()
to yield iterables instead of lists.
For many readers who would land on this page, as they are looking for a solution which fulfills this objective, this packages offers several advantages: i) code is always up-to-date, ii) many other useful functions are present.
s = [1,2,3,4,5,6,7,8,9]
size = 4
chuck_list = [s[i:i+size] for i in range(0, len(s), size)]
I found the following code that is compatible with python2
from itertools import izip_longest
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
However, this isn’t working with Python 3. I get the following error
ImportError: cannot import name izip_longest
Can someone help?
I’d like to convert my list of [1,2,3,4,5,6,7,8,9]
to [[1,2,3],[4,5,6],[7,8,9]]
Edit
Now Python3 compatible
Code below is adapted from the selected answer. Simply change name from izip_longest
to zip_longest
.
from itertools import zip_longest
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
In Python 3’s itertools
there is a function called zip_longest
. It should do the same as izip_longest
from Python 2.
Why the change in name? You might also notice that itertools.izip
is now gone in Python 3 – that’s because in Python 3, the zip
built-in function now returns an iterator, whereas in Python 2 it returns a list. Since there’s no need for the izip
function, it also makes sense to rename the _longest
variant for consistency.
According to the doc:
>>> s = [1,2,3,4,5,6,7,8,9]
>>> n = 3
>>> list(zip(*[iter(s)]*n))
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
After all that discussion above, here’s a python3 solution that I believe gives safer, more predicable results.
def chunker(iter, size):
chunks = [];
if size < 1:
raise ValueError('Chunk size must be greater than 0.')
for i in range(0, len(iter), size):
chunks.append(iter[i:(i+size)])
return chunks
example = [1,2,3,4,5,6,7,8,9]
print(' 1: ' + str(chunker(example, 1)))
print(' 3: ' + str(chunker(example, 3)))
print(' 4: ' + str(chunker(example, 4)))
print(' 8: ' + str(chunker(example, 8)))
print(' 9: ' + str(chunker(example, 9)))
print('10: ' + str(chunker(example, 10)))
The results are:
$ python3 iter_chunk.py
1: [[1], [2], [3], [4], [5], [6], [7], [8], [9]]
3: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
4: [[1, 2, 3, 4], [5, 6, 7, 8], [9]]
8: [[1, 2, 3, 4, 5, 6, 7, 8], [9]]
9: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
10: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
The source code of the grouper()
function included in the question is copied from the documentation for itertools
, more specifically the section Itertools Recipes.
In this documentation, it is stated that:
This section shows recipes for creating an extended toolset using the existing
itertools
as building blocks.Substantially all of these recipes and many, many others can be installed from the
more-itertools
project found on the Python Package Index:pip install more-itertools
If you look at the documentation of the more-itertools
package, then you will notice that the objective pursued in the question, i.e. to chunk a list, could be achieved with the following functions present in this package:
sliced()
to yield a list from sliceable iterables,chunked()
to yield a list from non-sliceable iterables.ichunked()
to yield iterables instead of lists.
For many readers who would land on this page, as they are looking for a solution which fulfills this objective, this packages offers several advantages: i) code is always up-to-date, ii) many other useful functions are present.
s = [1,2,3,4,5,6,7,8,9]
size = 4
chuck_list = [s[i:i+size] for i in range(0, len(s), size)]