计算生成器/迭代器中项目数的最短方法是什么?

2024-09-30 16:25:42 发布

您现在位置:Python中文网/ 问答频道 /正文

如果我想在不考虑元素本身的情况下获得一个iterable中的项目数,那么python的方法是什么?现在,我要定义

def ilen(it):
    return sum(itertools.imap(lambda _: 1, it))    # or just map in Python 3

但我知道lambda几乎被认为是有害的,而且lambda _: 1肯定不好看。

(此用例计算文本文件中与正则表达式匹配的行数,即grep -c


Tags: or方法lambda元素return定义def情况
3条回答

一条捷径是:

def ilen(it):
    return len(list(it))

请注意,如果您正在生成元素的lot(例如,数万个或更多),那么将它们放入列表可能会成为性能问题。然而,这只是一个简单的想法表达,在大多数情况下,性能并不重要。

通常的方法是

sum(1 for i in it)

方法,该方法在iterable可能很长时比sum(1 for i in it)快(在iterable很短时不比len(list(it))慢),同时保持固定的内存开销行为(与len(list(it))不同),以避免为较大的输入交换抖动和重新分配开销:

# On Python 2 only, get zip that lazily generates results instead of returning list
from future_builtins import zip

from collections import deque
from itertools import count

def ilen(it):
    # Make a stateful counting iterator
    cnt = count()
    # zip it with the input iterator, then drain until input exhausted at C level
    deque(zip(it, cnt), 0) # cnt must be second zip arg to avoid advancing too far
    # Since count 0 based, the next value is the count
    return next(cnt)

len(list(it))一样,它在CPython上执行C代码循环(dequecountzip都在C中实现);避免每个循环执行字节代码通常是CPython性能的关键。

很难找到公平的测试用例来比较性能(list欺骗使用的__length_hint__不太可能适用于任意输入的iterable,itertools不提供__length_hint__的函数通常有特殊的操作模式,当每个循环返回的值在释放之前释放时工作得更快下一个值被请求,使用maxlen=0deque将执行此操作)。我使用的测试用例是创建一个生成器函数,该函数接受输入并返回一个缺少特殊的itertools返回容器优化或__length_hint__的C级生成器,使用Python 3.3的yield from

def no_opt_iter(it):
    yield from it

然后使用ipython%timeit魔术(用不同的常数替换100):

>>> %%timeit -r5 fakeinput = (0,) * 100
... ilen(no_opt_iter(fakeinput))

当输入不够大以至于len(list(it))会导致内存问题时,在运行Python 3.5x64的Linux机器上,无论输入长度如何,我的解决方案比def ilen(it): return len(list(it))长大约50%。

对于最小的输入,调用deque/zip/count/next的设置成本意味着这样做比def ilen(it): sum(1 for x in it)花费的时间要长得多(在我的机器上,长度为0的输入要多200纳秒,比简单的sum方法多33%),但对于更长的输入,每个额外元素的运行时间大约是前者的一半;对于长度为5的输入,成本是相等的,并且在长度为50-100的范围内,与实际工作相比,初始开销是不明显的;sum方法大约需要两倍的时间。

基本上,如果内存使用问题或输入没有限制大小,并且您关心的是速度而不是简洁性,那么使用这个解决方案。如果输入是有界的并且很小,len(list(it))可能是最好的,如果它们是无界的,但是简单性/简洁性很重要,那么可以使用sum(1 for x in it)

相关问题 更多 >