3 回答

TA贡献1802条经验 获得超6个赞
一种方法是先查看第一个元素(如果有),然后创建并返回实际的生成器。
def head(iterable, max=10):
first = next(iterable) # raise exception when depleted
def head_inner():
yield first # yield the extracted first element
for cnt, el in enumerate(iterable):
yield el
if cnt + 1 >= max: # cnt + 1 to include first
break
return head_inner()
只需在chunk生成器中使用它,并StopIteration像处理自定义异常一样捕获异常即可。
更新:这是另一个版本,itertools.islice用于替换大部分head功能和一个for循环。这个简单for的事实,循环做同样的事情为笨重的while-try-next-except-break原代码构造,所以结果是很多的可读性。
def chunks(iterable, size=10):
iterator = iter(iterable)
for first in iterator: # stops when iterator is depleted
def chunk(): # construct generator for next chunk
yield first # yield element from for loop
for more in islice(iterator, size - 1):
yield more # yield more elements from the iterator
yield chunk() # in outer generator, yield next chunk
使用itertools.chain替换内部生成器,我们可以得到比这更短的代码:
def chunks(iterable, size=10):
iterator = iter(iterable)
for first in iterator:
yield chain([first], islice(iterator, size - 1))

TA贡献1828条经验 获得超6个赞
由于(在CPython中)使用了纯C级内置函数,因此我可以提出最快的解决方案。这样,就不需要Python字节码来生成每个块(除非在Python中实现了底层生成器),这具有巨大的性能优势。它确实在返回每个块之前先遍历了每个块,但是它没有对要返回的块进行任何预遍历:
# Py2 only to get generator based map
from future_builtins import map
from itertools import islice, repeat, starmap, takewhile
# operator.truth is *significantly* faster than bool for the case of
# exactly one positional argument
from operator import truth
def chunker(n, iterable): # n is size of each chunk; last chunk may be smaller
return takewhile(truth, map(tuple, starmap(islice, repeat((iter(iterable), n)))))
由于有点密集,请展开图进行说明:
def chunker(n, iterable):
iterable = iter(iterable)
while True:
x = tuple(islice(iterable, n))
if not x:
return
yield x
包装对chunkerin 的调用enumerate将使您可以根据需要对块进行编号。
添加回答
举报