Python 3生成器理解生成包括last的块

daw*_*awg 11 python generator python-3.x

如果您在Python 3.7中有一个列表:

>>> li
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Run Code Online (Sandbox Code Playgroud)

您可以n使用两种常见的Python习语之一将其转换为每个长度的块列表:

>>> n=3
>>> list(zip(*[iter(li)]*n))
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
Run Code Online (Sandbox Code Playgroud)

因为(9,10)不是长度,所以丢弃最后一个不完整的元组n

你也可以这样做:

>>> [li[i:i+n] for i in range(0,len(li),n)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
Run Code Online (Sandbox Code Playgroud)

如果你想要最后一个子列表,即使它有少于n元素.

假设我现在有一个发电机,gen未知长度或终端(所以呼叫list(gen))sum(1 for _ in gen)不明智)我想要每个块.

我能够想出的最好的生成器表达式是这样的:

from itertools import zip_longest
sentinel=object()             # for use in filtering out ending chunks
gen=(e for e in range(22))    # fill in for the actual gen

g3=(t if sentinel not in t else tuple(filter(lambda x: x != sentinel, t)) for t in zip_longest(*[iter(gen)]*n,fillvalue=sentinel))
Run Code Online (Sandbox Code Playgroud)

这适用于预期目的:

>>> next(g3)
(0, 1, 2)
>>> next(g3)
(3, 4, 5)
>>> list(g3)
[(6, 7, 8), (9, 10)]
Run Code Online (Sandbox Code Playgroud)

看起来很笨拙.我试过了:

  1. 使用islice但缺乏长度似乎难以克服;
  2. 使用sentinel iter但是sentinel版本iter需要一个可调用的,而不是可迭代的.

是否有一个更惯用的Python 3技术用于长度的块生成器,n包括可能小于的最后一个chuck n

我也对生成器功能持开放态度.我正在寻找一些惯用的东西,而且更具可读性.


更新:

我认为DSM在他删除的答案中的方法非常好:

>>> g3=(iter(lambda it=iter(gen): tuple(islice(it, n)), ()))
>>> next(g3)
(0, 1, 2)
>>> list(g3)
[(3, 4, 5), (6, 7, 8), (9, 10)]
Run Code Online (Sandbox Code Playgroud)

我打开这个问题是一个DUP,但链接的问题是近10岁的重点名单.在Python 3中没有新的方法,你不知道长度并且一次不想要一块以上的生成器吗?

cs9*_*s95 8

我认为只要你试图把它装进一个班轮里,这总是会很混乱.我会咬紧牙关,在这里使用发电机功能.如果您不知道实际大小(例如,如果gen是无限生成器等),则特别有用.

from itertools import islice

def chunk(gen, k):
    """Efficiently split `gen` into chunks of size `k`.

       Args:
           gen: Iterator to chunk.
           k: Number of elements per chunk.

       Yields:
           Chunks as a list.
    """ 
    while True:
        chunk = [*islice(gen, 0, k)]
        if chunk:
            yield chunk
        else:
            break
Run Code Online (Sandbox Code Playgroud)

>>> gen = iter(list(range(11)))
>>> list(chunk(gen))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
Run Code Online (Sandbox Code Playgroud)

有人可能会有更好的建议,但这就是我要做的.


归档时间:

查看次数:

359 次

最近记录:

7 年,5 月 前