首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python3生成器理解以生成块,包括last

Python3生成器理解以生成块,包括last
EN

Stack Overflow用户
提问于 2018-07-20 23:56:17
回答 8查看 585关注 0票数 11

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

代码语言:javascript
复制
>>> li
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

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

代码语言:javascript
复制
>>> n=3
>>> list(zip(*[iter(li)]*n))
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

由于(9,10)不是长度为n的元组,因此将丢弃最后一个不完整的元组

您还可以执行以下操作:

代码语言:javascript
复制
>>> [li[i:i+n] for i in range(0,len(li),n)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

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

假设现在我有一个生成器,gen,未知的长度或终止(所以调用list(gen))sum(1 for _ in gen)将不是明智之举),我想要每个块。

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

代码语言:javascript
复制
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))

为预期的目的工作:

代码语言:javascript
复制
>>> next(g3)
(0, 1, 2)
>>> next(g3)
(3, 4, 5)
>>> list(g3)
[(6, 7, 8), (9, 10)]

只是看起来--笨拙。我试过了:

  1. 使用islice但是长度的缺乏似乎很难在iter中调用一个islice,但是iter的前哨版本需要一个可调用的,而不是一个可迭代的。

有没有一种更常用的Python3技术来生成长度为n的块,包括可能小于n的最后一个块

我也对生成器函数持开放态度。我正在寻找一些地道的和大多数更具可读性的东西。

更新:

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

代码语言:javascript
复制
>>> 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)]

作为一个dup,我对这个问题持开放态度,但这个链接的问题已经有10年的历史了,并且集中在一个列表上。在Python3的生成器中没有新的方法,你不知道它的长度,并且一次只想要一个块吗?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2018-07-21 00:09:18

我认为只要你想把它放在一个线条里,这就会变得一团糟。我会咬紧牙关,在这里使用一个生成器函数。如果您不知道实际大小(例如,如果gen是无限生成器等),则特别有用。

代码语言:javascript
复制
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

代码语言:javascript
复制
>>> gen = iter(list(range(11)))
>>> list(chunk(gen))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

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

票数 9
EN

Stack Overflow用户

发布于 2018-07-21 00:16:50

这感觉像是一种构建在itertools上的非常合理的方法。

代码语言:javascript
复制
>>> g = (i for i in range(10))
>>> g3 = takewhile(lambda x: x, (list(islice(g,3)) for _ in count(0)))
>>> list(g3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
票数 3
EN

Stack Overflow用户

发布于 2018-07-22 01:47:59

我在这里整理了一些答案的时间。

我最初编写它的方式实际上是Python3.7上最快的。对于one liner来说,这可能是最好的。

修改后的cold speed的answer既快速,又具有Python化和可读性。

其他的答案都是相似的速度。

基准测试:

代码语言:javascript
复制
from __future__ import print_function

try:
    from itertools import zip_longest, takewhile, islice, count 
except ImportError:
    from itertools import takewhile, islice, count  
    from itertools import izip_longest as zip_longest
from collections import deque 

def f1(it,k):
    sentinel=object()
    for t in (t if sentinel not in t else tuple(filter(lambda x: x != sentinel, t)) for t in zip_longest(*[iter(it)]*k, fillvalue=sentinel)):
        yield t

def f2(it,k): 
    for t in (iter(lambda it=iter(it): tuple(islice(it, k)), ())):
        yield t

def f3(it,k):
    while True:
        chunk = (*islice(it, 0, k),)   # tuple(islice(it, 0, k)) if Python < 3.5
        if chunk:
            yield chunk
        else:
            break

def f4(it,k):
    for t in takewhile(lambda x: x, (tuple(islice(it,k)) for _ in count(0))):
        yield t

if __name__=='__main__':
    import timeit    
    def tf(f, k, x):
        data=(y for y in range(x))
        return deque(f(data, k), maxlen=3)

    k=3
    for f in (f1,f2,f3,f4):
        print(f.__name__, tf(f,k,100000))
    for case, x in (('small',10000),('med',100000),('large',1000000)):  
        print("Case {}, {:,} x {}".format(case,x,k))
        for f in (f1,f2,f3,f4):
            print("   {:^10s}{:.4f} secs".format(f.__name__, timeit.timeit("tf(f, k, x)", setup="from __main__ import f, tf, x, k", number=10)))    

结果是:

代码语言:javascript
复制
f1 deque([(99993, 99994, 99995), (99996, 99997, 99998), (99999,)], maxlen=3)
f2 deque([(99993, 99994, 99995), (99996, 99997, 99998), (99999,)], maxlen=3)
f3 deque([(99993, 99994, 99995), (99996, 99997, 99998), (99999,)], maxlen=3)
f4 deque([(99993, 99994, 99995), (99996, 99997, 99998), (99999,)], maxlen=3)
Case small, 10,000 x 3
       f1    0.0125 secs
       f2    0.0231 secs
       f3    0.0185 secs
       f4    0.0250 secs
Case med, 100,000 x 3
       f1    0.1239 secs
       f2    0.2270 secs
       f3    0.1845 secs
       f4    0.2477 secs
Case large, 1,000,000 x 3
       f1    1.2140 secs
       f2    2.2431 secs
       f3    1.7967 secs
       f4    2.4697 secs
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51446327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档