mat*_*ieu 68 python algorithm generator chunking
可能重复:
如何在Python中将列表拆分为大小均匀的块?
我很惊讶我找不到一个"批处理"函数,它将输入迭代并返回一个可迭代的迭代.
例如:
for i in batch(range(0,10), 1): print i
[0]
[1]
...
[9]
Run Code Online (Sandbox Code Playgroud)
要么:
for i in batch(range(0,10), 3): print i
[0,1,2]
[3,4,5]
[6,7,8]
[9]
Run Code Online (Sandbox Code Playgroud)
现在,我写了一个我认为非常简单的生成器:
def batch(iterable, n = 1):
current_batch = []
for item in iterable:
current_batch.append(item)
if len(current_batch) == n:
yield current_batch
current_batch = []
if current_batch:
yield current_batch
Run Code Online (Sandbox Code Playgroud)
但上面没有给我我所期望的:
for x in batch(range(0,10),3): print x
[0]
[0, 1]
[0, 1, 2]
[3]
[3, 4]
[3, 4, 5]
[6]
[6, 7]
[6, 7, 8]
[9]
Run Code Online (Sandbox Code Playgroud)
所以,我错过了一些东西,这可能表明我完全缺乏对python生成器的理解.有人会关心我指向正确的方向吗?
[编辑:我最终意识到只有当我在ipython而不是python本身中运行时才会发生上述行为]
Car*_* F. 92
这可能更有效(更快)
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
for x in batch(range(0, 10), 3):
print x
Run Code Online (Sandbox Code Playgroud)
它避免了构建新列表.
Ray*_*ger 37
FWIW,itertools模块中的配方提供了这个例子:
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
Run Code Online (Sandbox Code Playgroud)
它的工作原理如下:
>>> list(grouper(3, range(10)))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
Run Code Online (Sandbox Code Playgroud)
don*_*mus 25
正如其他人所说,您提供的代码完全符合您的要求.对于另一种使用方法,itertools.islice您可以看到以下配方的示例:
from itertools import islice, chain
def batch(iterable, size):
sourceiter = iter(iterable)
while True:
batchiter = islice(sourceiter, size)
yield chain([batchiter.next()], batchiter)
Run Code Online (Sandbox Code Playgroud)
Yon*_* Wu 22
More-itertools包括两个功能,可以满足您的需求:
chunked(iterable, n)返回一个可迭代的列表,每个列表的长度n(除了最后一个,可能更短);ichunked(iterable, n)是类似的,但返回一个可迭代的迭代。Yon*_* Wu 10
这是一个非常短的代码片段,我知道它len在 Python 2 和 3(不是我的创作)下不使用和工作:
def chunks(iterable, size):
from itertools import chain, islice
iterator = iter(iterable)
for first in iterator:
yield list(chain([first], islice(iterator, size - 1)))
Run Code Online (Sandbox Code Playgroud)
很奇怪,似乎在Python 2.x中对我很好
>>> def batch(iterable, n = 1):
... current_batch = []
... for item in iterable:
... current_batch.append(item)
... if len(current_batch) == n:
... yield current_batch
... current_batch = []
... if current_batch:
... yield current_batch
...
>>> for x in batch(range(0, 10), 3):
... print x
...
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
Run Code Online (Sandbox Code Playgroud)
Python 3.8 的解决方案,如果您正在使用未定义len函数的可迭代对象,并且感到筋疲力尽:
from itertools import islice
def batcher(iterable, batch_size):
iterator = iter(iterable)
while batch := list(islice(iterator, batch_size)):
yield batch
Run Code Online (Sandbox Code Playgroud)
用法示例:
def my_gen():
yield from range(10)
for batch in batcher(my_gen(), 3):
print(batch)
>>> [0, 1, 2]
>>> [3, 4, 5]
>>> [6, 7, 8]
>>> [9]
Run Code Online (Sandbox Code Playgroud)
当然也可以在没有海象运算符的情况下实现。
小智 5
python 3.8 中没有新功能的可行版本,改编自 @Atra Azami 的答案。
import itertools
def batch_generator(iterable, batch_size=1):
iterable = iter(iterable)
while True:
batch = list(itertools.islice(iterable, batch_size))
if len(batch) > 0:
yield batch
else:
break
for x in batch_generator(range(0, 10), 3):
print(x)
Run Code Online (Sandbox Code Playgroud)
输出:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
Run Code Online (Sandbox Code Playgroud)
我喜欢这一个,
def batch(x, bs):
return [x[i:i+bs] for i in range(0, len(x), bs)]
Run Code Online (Sandbox Code Playgroud)
这会返回 size 的批次列表,当然bs您可以使用生成器表达式将其设为生成器。(i for i in iterable)