我遇到了two different ways将iterable
拆分为“块”(超过1个项目)。
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
the other method is straight python:
def chunker(seq, size):
return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
itertools实施是否会为您带来“额外”的收益?
“额外”的地方,可能更快,更灵活或更安全。
我问,因为这里显示的itertools实现肯定不是更易读/直观的IMO。
答案 0 :(得分:5)
grouper
可以与任何 iterable一起使用 - 包括生成器和无限迭代器。
chunker
只能与sequences一起使用 - 可提前知道其长度的迭代。
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
def chunker(seq, size):
return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
x = (i**2 for i in range(5))
print(list(grouper(x, 3)))
# [(0, 1, 4), (9, 16, None)]
print(list(chunker(x, 3)))
# TypeError: object of type 'generator' has no len()
答案 1 :(得分:1)
这两个功能并不相同。有几点不同:
您的grouper
适用于任何迭代,包括迭代器和生成器,而chunker
需要支持索引的序列([...]
)。
>>> it = lambda : (i for i in range(6)) # creates a generator when called
>>> list(grouper(it(), 3))
[(0, 1, 2), (3, 4, 5)]
>>> list(chunker(it(), 3))
TypeError: object of type 'generator' has no len()
请注意,另一个答案已经提到了这一点!
如果chunksize不是长度的除数,则chunker
的最后一个元素将小于chunksize。 OTOH grouper
将填充一些fillvalue。另外chunker
将返回与原始相同的类型,而grouper
将返回tuple
s:
>>> list(grouper([1,2,3,4,5], 3))
[(1, 2, 3), (4, 5, None)]
>>> list(chunker([1,2,3,4,5], 3))
[[1, 2, 3], [4, 5]]
grouper
使用高性能内置插件iter
和zip_longest
。这些将非常快。以可读性为代价。但是,这可以比chunker
:
l = list(range(10000))
%timeit list(grouper(l, 10))
# 320 µs ± 6.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit list(chunker(l, 10))
# 1.22 ms ± 19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
所以grouper
是一种比chunker
更快,更通用的方法。但是根据具体情况,使用chunker
可能更有用,例如,如果您不喜欢“填充”部分或想要保留“块”的类型。