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

将另一个iterable分组为N组的Python生成器,python,generator,std,Python,Generator,Std,我正在寻找一个函数,它接受一个iterableI和一个sizen并生成长度为n的元组,这些元组是I的顺序值: x = [1,2,3,4,5,6,7,8,9,0] [z for z in TheFunc(x,3)] 给予 标准库中是否存在这样的函数 如果它作为标准库的一部分存在,我似乎找不到它,而且我已经没有可搜索的术语了。我可以自己写,但我宁愿不写。请参阅 (不过,这是一个复制品。)这个怎么样?但它没有填充值 >>> def partition(itr, n): ...

我正在寻找一个函数,它接受一个iterable
I
和一个size
n
并生成长度为
n
的元组,这些元组是
I
的顺序值:

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

标准库中是否存在这样的函数


如果它作为标准库的一部分存在,我似乎找不到它,而且我已经没有可搜索的术语了。我可以自己写,但我宁愿不写。

请参阅


(不过,这是一个复制品。)

这个怎么样?但它没有填充值

>>> 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]]
>>>
它使用原始iterable的副本,每个后续拼接都会使用该副本。我疲惫的大脑唯一能想到的另一个方法是用范围生成拼接端点

也许我应该将
list()
更改为
tuple()
,这样它才能更好地与您的输出相对应。

当您想将迭代器分组为
n
块而不填充时使用填充值的最后一个组,请使用
iter(lambda:list(it.islice(iterable,n)),[])
:

    def grouper(iterable, n):
        while True:
            yield itertools.chain((next(iterable),), itertools.islice(iterable, n-1))
屈服

[[1, 2, 3], [4, 5, 6], [7]]
在本书的后半部分有一个关于它如何工作的解释


如果要将迭代器分组为
n
块,并用填充值填充最后一个组,请使用
zip\u最长(*[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
块时,您可以使用
配方:


请注意,与一般的迭代器不同,它有一个长度(即定义了
\uu len\uu

我知道这已经被回答了好几次,但我正在添加我的解决方案,它应该在这两方面都有所改进,对序列和迭代器的通用性,可读性(StopIteration异常没有不可见的循环退出条件)与石斑鱼配方相比,它的性能更好。这与斯文的最后一个答案最为相似

def chunkify(iterable,n):
iterable=iter(iterable)
n_rest=n-1
对于iterable中的项目:
rest=itertools.islice(iterable,n_rest)
收益率itertools.链((项目),剩余)

这里有一个不同的解决方案,它不使用itertools,而且,即使它还有几行,当块比iterable长度短得多时,它的性能显然优于给定的答案。 然而,对于大块,其他答案要快得多

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

这是Python中非常常见的请求。足够普通,因此它被纳入了统一的实用程序包中。首先。此外,它的设计和测试仅依赖于标准库(与Python 2和3兼容),这意味着您可以

#如果已下载/嵌入,请尝试:
#从iterutils进口大块
#使用“pip安装螺栓”使用:
从boltons.iterutils导入块
打印(分块(范围(10),3))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
不定/长序列也有迭代器/生成器形式:

print(列表(分块)(范围(10),3,填充=无)))
#[0,1,2],[3,4,5],[6,7,8],[9,无,无]]
如您所见,您还可以使用您选择的值填充序列。最后,作为维护人员,我可以向您保证,尽管数千名开发人员已经下载/测试了代码,但如果您遇到任何问题,您将通过Web获得尽可能快的支持。希望这个(和/或其他150多个博尔顿食谱中的任何一个)有帮助

我用的是


这是一个非常古老的问题,但我认为在一般情况下提及以下方法是有用的。它的主要优点是只需要对数据进行一次迭代,因此它可以使用数据库游标或其他只能使用一次的序列。我还发现它更具可读性

def chunks(n, iterator):
    out = []
    for elem in iterator:
        out.append(elem)
        if len(out) == n:
            yield out
            out = []
    if out:
        yield out

如果我知道搜索“石斑鱼”,我根本不需要问。但我不知道这个词。完全忘记了文档中方便的配方。我最终使用了这个,但不得不在稍后阶段过滤掉填充值。很高兴知道,但没有回答这个问题,因为OP想要最后一块而不填充。如果你在代码中包含一个简短的解释,你的答案会更好。哈哈。你一定是在开玩笑。答案中有一个bug,我对它的编辑被拒绝了?我对SO社区的尊重已经大大降低了。顺便说一句,itertools.islice(i,0,3)->itertools.islice(i,0,n)仍然不能相信SO社区。我没有拒绝它,其他人拒绝了。但你是对的。3是硬编码的,否定了n作为参数的用途。如果你想,我可以编辑它,但你不会得到任何代表,然后,由你:)是的……我现在已经有点忘记了。你可以自己编辑:)这是最优雅的答案。唯一的问题是,它可以返回一个空列表作为最后一个块。在最后一行之前添加
if len(out)>0:
来解决这个问题。这个答案很好,对我帮助很大。非常感谢。
>>> list(IT.zip_longest(*[iter(seq)]*3, fillvalue='x'))
[(1, 2, 3), (4, 5, 6), (7, 'x', 'x')]
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]
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
$ 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,)]
def chunks(n, iterator):
    out = []
    for elem in iterator:
        out.append(elem)
        if len(out) == n:
            yield out
            out = []
    if out:
        yield out