一般来说,有没有一种有效的方法可以知道Python中的迭代器中有多少个元素,而不用遍历每个元素并计数?


当前回答

不。这是不可能的。

例子:

import random

def gen(n):
    for i in xrange(n):
        if random.randint(0, 1) == 0:
            yield i

iterator = gen(10)

迭代器的长度是未知的,直到迭代遍历它。

其他回答

通常的做法是将这类信息放在文件头中,并让pysam允许您访问这些信息。我不知道格式,但是你检查过API了吗?

正如其他人所说,你不能从迭代器中知道长度。

这段代码应该工作:

>>> 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迭代器设计的一个不可避免的结果。如果你想保留元素,你就必须把它们存储在一个列表或其他东西中。

所以,对于那些想知道讨论总结的人。使用以下方法计算5000万长度生成器表达式的最终最高分:

len(列表(创)), Len ([_ for _ in gen]), Sum (1 for _ in gen), Ilen (gen) (from more_itertool), Reduce (c, i: c + 1, gen, 0),

按执行性能排序(包括内存消耗),会让你大吃一惊:

```

1: test_list.py: 8:0.492 KiB

gen = (i for i in data*1000); t0 = monotonic(); len(list(gen))

('list, sec', 1.9684218849870376)

2: test_list_compr.py: 8:0.867 KiB

gen = (i for i in data*1000); t0 = monotonic(); len([i for i in gen])

('list_compr, sec', 2.5885991149989422)

3: test_sum.py:8: 0.859 KiB

gen = (i for i in data*1000); t0 = monotonic(); sum(1 for i in gen); t1 = monotonic()

('sum, sec', 3.441088170016883)

4: more_itertools/more.py:413: 1.266 KiB

d = deque(enumerate(iterable, 1), maxlen=1)

test_ilen.py:10: 0.875 KiB
gen = (i for i in data*1000); t0 = monotonic(); ilen(gen)

(ilen, sec, 9.812256851990242)

5: test_reduce.py:8: 0.859 KiB

gen = (i for i in data*1000); t0 = monotonic(); reduce(lambda counter, i: counter + 1, gen, 0)

('reduce, sec', 13.436614598002052) ' ' '

因此,len(list(gen))是使用频率最高且占用内存较少的

不,任何方法都需要解析每个结果。你可以这样做

iter_length = len(list(iterable))

但是在无限迭代器上运行它当然不会返回。它还将消耗迭代器,如果你想使用内容,它将需要重置。

告诉我们你想要解决的真正问题可能会帮助我们找到更好的方法来实现你的实际目标。

编辑:使用list()会将整个可迭代对象一次性读入内存,这可能是不可取的。另一种方法是做

sum(1 for _ in iterable)

正如另一个人发布的那样。这样可以避免把它保存在记忆中。

这违背了迭代器的定义,迭代器是一个指向对象的指针,加上如何到达下一个对象的信息。

迭代器不知道在终止之前它还能迭代多少次。这个可以是无穷,所以无穷可能是你的答案。