Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python3生成器理解生成块,包括最后一个_Python_Python 3.x_Generator - Fatal编程技术网

Python3生成器理解生成块,包括最后一个

Python3生成器理解生成块,包括最后一个,python,python-3.x,generator,Python,Python 3.x,Generator,如果在Python 3.7中有一个列表: >>> li [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 您可以使用两种常见的Python习惯用法之一将其转换为一个块列表,每个块的长度n: >>> n=3 >>> list(zip(*[iter(li)]*n)) [(0, 1, 2), (3, 4, 5), (6, 7, 8)] 从(9,10)开始删除最后一个不完整的元组不是长度n 您还可以执行以下操作: >&g

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

>>> li
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
您可以使用两种常见的Python习惯用法之一将其转换为一个块列表,每个块的长度
n

>>> n=3
>>> list(zip(*[iter(li)]*n))
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
(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]]
如果您想要最后一个子列表,即使它的元素少于
n

假设现在我有一个生成器,
gen
,未知长度或终止(因此调用
list(gen))
sum(1代表uuu-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))
为预期目的工作:

>>> next(g3)
(0, 1, 2)
>>> next(g3)
(3, 4, 5)
>>> list(g3)
[(6, 7, 8), (9, 10)]
只是看起来很笨拙。我试过:

  • 使用
    islice
    但长度不足似乎难以克服
  • iter
    中使用哨兵,但是
    iter
    的哨兵版本需要可调用的,而不是可调用的
  • 对于长度
    n
    的块生成器(包括可能小于
    n
    的最后一个卡盘),是否有一种更惯用的Python 3技术

    我也对发电机功能持开放态度。我正在寻找一些惯用的、更具可读性的东西


    更新:

    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)]
    


    我对这个问题持开放态度,但这个相关的问题已经有近10年的历史了,主要集中在一个列表上。在Python3中,没有一种新的方法可以生成不知道长度并且一次只需要一个块的生成器

    我认为,只要你想把它放进一行中,这件事就会变得一团糟。 我会咬紧牙关,在这里使用发电机功能。如果您不知道实际大小(例如,如果
    gen
    是一个无限大的生成器,等等),则特别有用


    有人可能会有更好的建议,但我会这样做。

    这个带有生成器函数的解决方案非常明确和简短:

    def g3(seq):
        it = iter(seq)
        while True:
            head = list(itertools.islice(it, 3))
            if head:
                yield head
            else:
                break
    

    这感觉像是一种基于itertools的非常合理的方法

    >>> 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]]
    

    我尝试使用
    groupby
    cycle
    。使用
    cycle
    可以选择一种模式来对元素进行分组,因此它的用途非常广泛:

    from itertools import groupby, cycle
    
    gen=(e for e in range(11))
    d = [list(g) for d, g in groupby(gen, key=lambda v, c=cycle('000111'): next(c))]
    print([v for v in d])
    
    产出:

    [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
    
    文档的部分提供了各种生成器帮助程序

    在这里,您可以使用第二种形式的修改
    take
    ,以创建块生成器

    from itertools import islice
    
    def chunks(n, it):
        it = iter(it)
        return iter(lambda: tuple(islice(it, n)), ())
    
    例子 输出
    我们可以使用itertools文档页面中给出的grouper函数来实现这一点

    from itertools import zip_longest
    
    def grouper(iterable, n, fillvalue=None):
        "Collect data into fixed-length chunks or blocks"
        # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
        args = [iter(iterable)] * n
        return zip_longest(fillvalue=fillvalue, *args)
    
    def out_iterator(lst):
        for each in grouper(lst,n):
            if None in each:
                yield each[:each.index(None)]
            else:
                yield each
    a=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    n=3
    print(list(out_iterator(a)))
    
    输出:

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

    我在这里列出了一些答案的时间安排

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

    cold speed’s的一个改进版本既快速又通俗易懂

    其他答案都是相似的速度

    基准:

    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)))    
    
    :

    另见:


    可能我误解了,但是
    islice
    像gen:print(tuple(islice(gen,3))中的
    那样的
    有什么问题呢?
    (用
    yield
    替换
    print
    ,当然是一个生成器函数)可能重复,@Kasramvd:啊,是的——我的答案只是其中一行有一个默认值,@Kasramvd:我不认为这些是完全重复的,因为1)大部分与内存中已经存在的列表有关,或者2)没有采用Python 3.6+的更新功能,3)与我列出的两个习惯用法有一些不同。相关问题已经有10年历史了。我们是否得出结论,没有新的Python3唯一的方法可以做到这一点?这既清晰又快速。(我对它们进行了基准测试…)谢谢时间安排;-)如果您想要元组列表和列表列表,还可以执行
    chunk=(*islice(it,0,k),)
    。在Python<3.5上,
    tuple(islice(it,0,k))
    (0, 1, 2) (3, 4, 5) (6, 7, 8) (9, 10)
    
    from itertools import zip_longest
    
    def grouper(iterable, n, fillvalue=None):
        "Collect data into fixed-length chunks or blocks"
        # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
        args = [iter(iterable)] * n
        return zip_longest(fillvalue=fillvalue, *args)
    
    def out_iterator(lst):
        for each in grouper(lst,n):
            if None in each:
                yield each[:each.index(None)]
            else:
                yield each
    a=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    n=3
    print(list(out_iterator(a)))
    
    [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10)]
    
    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)))    
    
    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
    
    list(more_itertools.chunked(range(11), 3))
    # [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
    
    iter(functools.partial(more_itertools.take, n, iter(iterable)), [])