What is pythons equivalent of Ruby's each_slice(count)
?
[1,2,3,4,5,6]
I want to handle 1,2
in first iteration then 3,4
then 5,6
.
Ofcourse there is a roundabout way using index values. But is there a direct function or someway to do this directly?There is a recipe for this in the itertools documentation called grouper:
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
Use like this:
>>> l = [1,2,3,4,5,6]
>>> for a,b in grouper(2, l):
>>> print a, b
1 2
3 4
5 6
I know this has been answered by multiple experts on the language, but I have a different approach using a generator function that is easier to read and reason about and modify according to your needs:
def each_slice(list: List[str], size: int):
batch = 0
while batch * size < len(list):
yield list[batch * size:(batch + 1) * size]
batch += 1
slices = each_slice(["a", "b", "c", "d", "e", "f", "g"], 2)
print([s for s in slices])
$ [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g']]
If you need each slice to be of batch size, maybe pad None, or some default character you can simply add padding code to the yield. If you want each_cons instead, you can do that by modifying the code to move one by one instead of batch by batch.
Duplicates ruby's each_slice behavior for a small trailing slice:
def each_slice(size, iterable):
""" Chunks the iterable into size elements at a time, each yielded as a list.
Example:
for chunk in each_slice(2, [1,2,3,4,5]):
print(chunk)
# output:
[1, 2]
[3, 4]
[5]
"""
current_slice = []
for item in iterable:
current_slice.append(item)
if len(current_slice) >= size:
yield current_slice
current_slice = []
if current_slice:
yield current_slice
The answers above will pad the last list (i.e., [5, None]), which may not be what is desired in some cases.
Same as Mark's but renamed to 'each_slice' and works for python 2 and 3:
try:
from itertools import izip_longest # python 2
except ImportError:
from itertools import zip_longest as izip_longest # python 3
def each_slice(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
An improvement on the first two: If the iterable being sliced is not exactly divisible by n, the last will be filled to the length n with None. If this is causing you type errors, you can make a small change:
def each_slice(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
raw = izip_longest(fillvalue=fillvalue, *args)
return [filter(None, x) for x in raw]
Keep in mind this will remove ALL None's from the range, so should only be used in cases where None will cause errors down the road.
s_size = 4
l = list(range(100))
while len(l) > 0:
slice = [l.pop() for _e,i in enumerate(l) if i <= s_size ]
print(slice)
精彩评论