将另一个iterable分组成N个Python组的Python生成器

我正在寻找一个函数,它需要一个可迭代的i和一个大小为n元组,并产生长度为n元组,它们是从i顺序值:

 x = [1,2,3,4,5,6,7,8,9,0] [z for z in TheFunc(x,3)] 

 [(1,2,3),(4,5,6),(7,8,9),(0)] 

标准库中是否有这样的function?

如果它存在作为标准库的一部分,我似乎无法find它,我已经用尽了条件search。 我可以自己写,但我宁愿不写。

请参阅itertools包的文档中的grouper配方

 def grouper(n, iterable, fillvalue=None): "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) 

(但是,这是相当多的问题的重复。)

当你想以n块为一个迭代器进行分组而不填充最后一个填充值时,使用iter(lambda: list(IT.islice(iterable, n)), [])

 import itertools as IT def grouper(n, iterable): """ >>> list(grouper(3, 'ABCDEFG')) [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']] """ iterable = iter(iterable) return iter(lambda: list(IT.islice(iterable, n)), []) seq = [1,2,3,4,5,6,7] print(list(grouper(3, seq))) 

产量

 [[1, 2, 3], [4, 5, 6], [7]] 

这个答案的后半部分有一个解释。


当你想将一个迭代器分成n块, 用填充值填充最后一个组时,使用石斑鱼配方 zip_longest(*[iterator]*n)

例如,在Python2中:

 >>> list(IT.izip_longest(*[iter(seq)]*3, fillvalue='x')) [(1, 2, 3), (4, 5, 6), (7, 'x', 'x')] 

在Python3中,什么是izip_longest现在更名为zip_longest

 >>> list(IT.zip_longest(*[iter(seq)]*3, fillvalue='x')) [(1, 2, 3), (4, 5, 6), (7, 'x', 'x')] 

当你想把一个序列分成n块时,你可以使用chunks配方

 def chunks(seq, n): # https://stackoverflow.com/a/312464/190597 (Ned Batchelder) """ Yield successive n-sized chunks from seq.""" for i in xrange(0, len(seq), n): yield seq[i:i + n] 

请注意,与通常的迭代器不同, 按照定义 , 序列有一个长度(即定义了__len__ )。

这个怎么样? 它虽然没有填充值。

 >>> def partition(itr, n): ... i = iter(itr) ... res = None ... while True: ... res = list(itertools.islice(i, 0, n)) ... if res == []: ... break ... yield res ... >>> list(partition([1, 2, 3, 4, 5, 6, 7, 8, 9], 3)) [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >>> 

它利用原始迭代的副本,这是每个连续拼接耗尽的。 我疲倦的大脑能够想出的唯一另外一种方式是产生具有范围的拼接终点。

也许我应该将list()更改为tuple()以便它更好地符合您的输出。

我使用more_itertools包中的分块函数 。

 $ pip install more_itertools $ python >>> x = [1,2,3,4,5,6,7,8,9,0] >>> [tuple(z) for z in more_itertools.more.chunked(x, 3)] [(1, 2, 3), (4, 5, 6), (7, 8, 9), (0,)] 

这是Python中的一个非常常见的请求。 它足够普遍,它使它成为boltons统一的实用程序包。 首先, 这里有大量的文档 。 此外, 模块的devise和testing只依赖标准库(Python 2和3兼容),这意味着您可以直接将文件下载到您的项目中 。

 # if you downloaded/embedded, try: # from iterutils import chunked # with `pip install boltons` use: from boltons.iterutils import chunked print(chunked(range(10), 3)) # [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] 

还有一个不确定/长序列的迭代器/生成器forms:

 print(list(chunked_iter(range(10), 3, fill=None))) # [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, None, None]] 

正如你所看到的,你也可以用你select的值填充序列。 最后,作为维护人员,我可以向您保证,尽pipe代码已经被成千上万的开发人员下载/testing,但是如果您遇到任何问题,您可以通过boltons GitHub Issues页面获得最快的支持。 希望这个(和/或任何其他150 + Boltons食谱)帮助!

这是一个非常古老的问题,但我认为在一般情况下提出以下方法是有益的。 它的主要优点是只需要对数据进行一次迭代,因此可以与数据库游标或其他只能使用一次的序列一起工作。 我也觉得它更可读。

 def chunks(n, iterator): out = [] for elem in iterator: out.append(elem) if len(out) == n: yield out out = [] yield out 
  def grouper(iterable, n): while True: yield itertools.chain(iterable.next(),itertools.islice(iterable, n-1)) 

我知道这已经被回答了好几次了,但是我join了我的解决scheme,这个scheme在序列和迭代器的普遍适用性,可读性(StopIterationexception没有看不见的循环退出条件)以及与石斑鱼配方相比的性能都有所提高。 这与斯文最后的回答最为相似。

 def chunkify(iterable, n): iterable = iter(iterable) n_rest = n - 1 for item in iterable: rest = itertools.islice(iterable, n_rest) yield itertools.chain((item,), rest) 

这是一个不使用itertools的不同的解决scheme,尽pipe它有更多的行,但是当块比可迭代长度短得多时,它显然胜过了给定的答案。 但是,对于大块其他答案要快得多。

 def batchiter(iterable, batch_size): """ >>> list(batchiter('ABCDEFG', 3)) [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']] """ next_batch = [] for element in iterable: next_batch.append(element) if len(next_batch) == batch_size: batch, next_batch = next_batch, [] yield batch if next_batch: yield next_batch In [19]: %timeit [b for b in batchiter(range(1000), 3)] 1000 loops, best of 3: 644 µs per loop In [20]: %timeit [b for b in grouper(3, range(1000))] 1000 loops, best of 3: 897 µs per loop In [21]: %timeit [b for b in partition(range(1000), 3)] 1000 loops, best of 3: 890 µs per loop In [22]: %timeit [b for b in batchiter(range(1000), 333)] 1000 loops, best of 3: 540 µs per loop In [23]: %timeit [b for b in grouper(333, range(1000))] 10000 loops, best of 3: 81.7 µs per loop In [24]: %timeit [b for b in partition(range(1000), 333)] 10000 loops, best of 3: 80.1 µs per loop