一般来说,有没有一种有效的方法可以知道Python中的迭代器中有多少个元素,而不用遍历每个元素并计数?
当前回答
我认为有必要建立一个微观基准来比较这里提到的不同方法的运行时间。
免责声明:我使用simple_benchmark(我编写的库)进行基准测试,还包括iteration_utilities。Count_items(由我编写的第三方库中的函数)。
为了提供更有区别的结果,我做了两个基准测试,一个只包括不构建中间容器的方法,另一个包括以下方法:
from simple_benchmark import BenchmarkBuilder
import more_itertools as mi
import iteration_utilities as iu
b1 = BenchmarkBuilder()
b2 = BenchmarkBuilder()
@b1.add_function()
@b2.add_function()
def summation(it):
return sum(1 for _ in it)
@b1.add_function()
def len_list(it):
return len(list(it))
@b1.add_function()
def len_listcomp(it):
return len([_ for _ in it])
@b1.add_function()
@b2.add_function()
def more_itertools_ilen(it):
return mi.ilen(it)
@b1.add_function()
@b2.add_function()
def iteration_utilities_count_items(it):
return iu.count_items(it)
@b1.add_arguments('length')
@b2.add_arguments('length')
def argument_provider():
for exp in range(2, 18):
size = 2**exp
yield size, [0]*size
r1 = b1.run()
r2 = b2.run()
import matplotlib.pyplot as plt
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=[15, 18])
r1.plot(ax=ax2)
r2.plot(ax=ax1)
plt.savefig('result.png')
结果如下:
它使用log-log-轴,以便可以检查所有范围(小值,大值)。由于这些图是用于定性比较的,因此实际值并不太有趣。一般来说,y轴(垂直)表示时间,x轴(水平)表示输入“可迭代对象”中的元素数量。纵轴上越低表示越快。
上图显示了不使用中间列表的方法。这表明iteration_utilities方法是最快的,其次是more_itertools,最慢的是使用sum(1 for _ in iterator)。
下面的图还包括在中间列表上使用len()的方法,一次使用列表,一次使用列表推导式。使用len(list)的方法在这里是最快的,但与iteration_utilities方法的区别几乎可以忽略不计。使用理解式的方法比直接使用列表的方法慢得多。
总结
这里提到的任何方法都依赖于输入的长度,并且迭代遍历可迭代对象中的每个元素。没有迭代就无法获得长度(即使迭代是隐藏的)。
如果你不想要第三方扩展,那么使用len(list(iterable))绝对是测试过的方法中最快的方法,但是它会生成一个中间列表,可能会使用更多的内存。
如果你不介意额外的包,那么iteration_utilities。Count_items几乎和len(list(…))函数一样快,但不需要额外的内存。
但是需要注意的是,微基准测试使用列表作为输入。基准测试的结果可能不同,这取决于您想要获取的迭代对象的长度。我还用range和一个简单的生成器表达式进行了测试,趋势非常相似,但我不能排除时间不会因输入类型而改变。
其他回答
一个简单的方法是使用内置函数set()或list():
答:set()在迭代器中没有重复项的情况下(最快的方式)
iter = zip([1,2,3],['a','b','c'])
print(len(set(iter)) # set(iter) = {(1, 'a'), (2, 'b'), (3, 'c')}
Out[45]: 3
or
iter = range(1,10)
print(len(set(iter)) # set(iter) = {1, 2, 3, 4, 5, 6, 7, 8, 9}
Out[47]: 9
B: list()以防迭代器中有重复的项
iter = (1,2,1,2,1,2,1,2)
print(len(list(iter)) # list(iter) = [1, 2, 1, 2, 1, 2, 1, 2]
Out[49]: 8
# compare with set function
print(len(set(iter)) # set(iter) = {1, 2}
Out[51]: 2
通常的做法是将这类信息放在文件头中,并让pysam允许您访问这些信息。我不知道格式,但是你检查过API了吗?
正如其他人所说,你不能从迭代器中知道长度。
不能(除非特定迭代器的类型实现了一些特定的方法,使之成为可能)。
通常,只能通过使用迭代器来计数迭代器项。最有效的方法之一:
import itertools
from collections import deque
def count_iter_items(iterable):
"""
Consume an iterable not reading it into memory; return the number of items.
"""
counter = itertools.count()
deque(itertools.izip(iterable, counter), maxlen=0) # (consume at C speed)
return next(counter)
(对于Python 3。X替换itertools。Izip with zip)。
有点。你可以检查__length_hint__方法,但要注意(至少在Python 3.4之前,正如gsnedders所指出的那样),它是一个未记录的实现细节(在线程中跟随消息),它很可能消失或召唤鼻子恶魔。
否则,没有。迭代器只是一个只公开next()方法的对象。你可以根据需要多次调用它,它们最终可能引发也可能不会引发StopIteration。幸运的是,大多数时候这种行为对编码器来说是透明的。:)
在计算机上有两种方法来获取“某物”的长度。
第一种方法是存储一个计数——这需要任何接触文件/数据的东西来修改它(或者一个只公开接口的类——但归根结底是一样的)。
另一种方法是遍历它并计算它有多大。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录