一般来说,有没有一种有效的方法可以知道Python中的迭代器中有多少个元素,而不用遍历每个元素并计数?
当前回答
假设,您希望在不遍历的情况下计算项的数量,这样迭代器就不会耗尽,稍后可以再次使用它。这是可能的复制或深度复制
import copy
def get_iter_len(iterator):
return sum(1 for _ in copy.copy(iterator))
###############################################
iterator = range(0, 10)
print(get_iter_len(iterator))
if len(tuple(iterator)) > 1:
print("Finding the length did not exhaust the iterator!")
else:
print("oh no! it's all gone")
输出是“查找长度没有耗尽迭代器!”
可选的(并且不明智的),你可以像下面这样为内置的len函数添加阴影:
import copy
def len(obj, *, len=len):
try:
if hasattr(obj, "__len__"):
r = len(obj)
elif hasattr(obj, "__next__"):
r = sum(1 for _ in copy.copy(obj))
else:
r = len(obj)
finally:
pass
return r
其他回答
通常的做法是将这类信息放在文件头中,并让pysam允许您访问这些信息。我不知道格式,但是你检查过API了吗?
正如其他人所说,你不能从迭代器中知道长度。
在计算机上有两种方法来获取“某物”的长度。
第一种方法是存储一个计数——这需要任何接触文件/数据的东西来修改它(或者一个只公开接口的类——但归根结底是一样的)。
另一种方法是遍历它并计算它有多大。
关于你最初的问题,答案仍然是,在Python中通常没有办法知道迭代器的长度。
Given that you question is motivated by an application of the pysam library, I can give a more specific answer: I'm a contributer to PySAM and the definitive answer is that SAM/BAM files do not provide an exact count of aligned reads. Nor is this information easily available from a BAM index file. The best one can do is to estimate the approximate number of alignments by using the location of the file pointer after reading a number of alignments and extrapolating based on the total size of the file. This is enough to implement a progress bar, but not a method of counting alignments in constant time.
我决定在现代版本的Python上重新运行基准测试,并发现几乎完全颠倒了基准测试
我运行了以下命令:
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " return len(tuple(x))" -- "itlen(it)"
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " return len(list(x))" -- "itlen(it)"
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " return sum(map(lambda i: 1, x))" -- "itlen(it)"
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " return sum(1 for _ in x)" -- "itlen(it)"
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " d = deque(enumerate(x, 1), maxlen=1)" -s " return d[0][0] if d else 0" -- "itlen(it)"
py -m timeit -n 10000000 -s "it = iter(range(1000000))" -s "from collections import deque" -s "from itertools import count" -s "def itlen(x):" -s " counter = count()" -s " deque(zip(x, counter), maxlen=0)" -s " return next(counter)" -- "itlen(it)"
它们等价于为以下每个itlen*(it)函数计时:
it = iter(range(1000000))
from collections import deque
from itertools import count
def itlen1(x):
return len(tuple(x))
def itlen2(x):
return len(list(x))
def itlen3(x):
return sum(map(lambda i: 1, x))
def itlen4(x):
return sum(1 for _ in x)
def itlen5(x):
d = deque(enumerate(x, 1), maxlen=1)
return d[0][0] if d else 0
def itlen6(x):
counter = count()
deque(zip(x, counter), maxlen=0)
return next(counter)
在装有AMD Ryzen 7 5800H和16 GB RAM的Windows 11、Python 3.11机器上,我得到了以下输出:
10000000 loops, best of 5: 103 nsec per loop
10000000 loops, best of 5: 107 nsec per loop
10000000 loops, best of 5: 138 nsec per loop
10000000 loops, best of 5: 164 nsec per loop
10000000 loops, best of 5: 338 nsec per loop
10000000 loops, best of 5: 425 nsec per loop
这表明len(list(x))和len(tuple(x))是绑定的;后面跟着sum(map(lambda i: 1, x));然后紧靠sum(1 for _ in x);那么其他答案中提到的其他更复杂的方法和/或在基数中使用的方法至少要慢两倍。
这段代码应该工作:
>>> iter = (i for i in range(50))
>>> sum(1 for _ in iter)
50
尽管它确实遍历每一项并计算它们,但这是最快的方法。
它也适用于迭代器中没有项的情况:
>>> sum(1 for _ in range(0))
0
当然,对于一个无限的输入,它会一直运行,所以请记住迭代器可以是无限的:
>>> sum(1 for _ in itertools.count())
[nothing happens, forever]
此外,请注意,这样做将耗尽迭代器,并且进一步尝试使用它将看不到任何元素。这是Python迭代器设计的一个不可避免的结果。如果你想保留元素,你就必须把它们存储在一个列表或其他东西中。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录