有没有内置的方法来获取python中迭代的长度?

Cla*_*diu 47 python iterator

例如,Python中的文件是可迭代的 - 它们遍历文件中的行.我想计算行数.

一个快速的方法是这样做:

lines = len(list(open(fname)))
Run Code Online (Sandbox Code Playgroud)

但是,这会将整个文件加载到内存中(一次).这相当违背了迭代器的目的(它只需要将当前行保留在内存中).

这不起作用:

lines = len(line for line in open(fname))
Run Code Online (Sandbox Code Playgroud)

因为发电机没有长度.

有没有办法做到这一点,没有定义计数功能?

def count(i):
    c = 0
    for el in i: c += 1
    return c
Run Code Online (Sandbox Code Playgroud)

编辑:澄清,我明白整个文件必须阅读!我只是不想在内存中一次性=).

Kam*_*iel 66

没有遍历迭代并计算迭代次数,没有.这就是使它成为可迭代而不是列表的原因.这甚至不是特定于python的问题.查看经典的链表数据结构.查找长度是O(n)操作,涉及迭代整个列表以查找元素的数量.

正如上面提到的那样,你可以将你的功能减少到:

def count_iterable(i):
    return sum(1 for e in i)
Run Code Online (Sandbox Code Playgroud)

当然,如果您要定义自己的可迭代对象,则可以始终实现__len__自己并在某处保留元素数.

  • 罢工itertools.tee.我总是忘记它必须将原始迭代器中的数据放在某个地方,这直接违背了操作的要求. (4认同)
  • 那就对了.如果您必须使用整个iterable来获取计数,那么您将有效地将所有数据加载到tee的临时存储中,直到它被其他迭代器使用为止. (2认同)

mcr*_*ute 20

如果你需要一个行数,你可以做到这一点,我不知道有任何更好的方法:

line_count = sum(1 for line in open("yourfile.txt"))
Run Code Online (Sandbox Code Playgroud)


tte*_*sse 11

我已经使用了这个重新定义了一段时间了:

def len(thingy):
    try:
        return thingy.__len__()
    except AttributeError:
        return sum(1 for item in iter(thingy))
Run Code Online (Sandbox Code Playgroud)

  • "谨慎使用"又名"我们都同意成年人",这是Python的原则之一.至少它是一次,一次. (3认同)
  • 没有理由在这里显式调用 `__len__` 或 `iter`;简单的`len(thingy)` 以标准方式调用`__len__`,并且迭代任何东西隐式地将其转换为迭代器,所以`for item in iter(thingy)` 只是一种更慢、更长的拼写`for item in 的方式东西`。 (2认同)

wou*_*lee 9

cardinality包提供了一个有效的count()函数和一些相关的函数来计算和检查任何iterable的大小:http://cardinality.readthedocs.org/

import cardinality

it = some_iterable(...)
print(cardinality.count(it))
Run Code Online (Sandbox Code Playgroud)

在内部,它使用enumerate()并将collections.deque()所有实际的循环和计数逻辑移动到C级别,从而for在Python中循环得到相当大的加速.


Tri*_*ych 8

绝对不是,原因很简单,因为不能保证迭代是有限的.

考虑这个完全合法的生成函数:

def forever():
    while True:
        yield "I will run forever"
Run Code Online (Sandbox Code Playgroud)

尝试计算此功能的长度len([x for x in forever()])显然不起作用.

正如您所指出的,迭代器/生成器的大部分用途是能够处理大型数据集而无需将其全部加载到内存中.您不能立即获得长度的事实应被视为权衡.

  • sum(),max()和min()也是如此,但这个聚合函数需要迭代. (22认同)
  • 我赞成这一点,主要是为了"绝对",这是不正确的.任何实现__len __()的东西都有一个长度 - 无限或无. (7认同)
  • @Triptych是的,但正如跳跃所说,从"绝对"开始意味着普遍适用性,包括所有特殊情况. (2认同)
  • 是的,如果给出无限生成器,它将永远不会终止.但这并不意味着这个想法在所有情况下都毫无意义.文档字符串中的一个简单警告表明了这种限制就足以正确使用. (2认同)

pyl*_*ang 8

事实证明,这个常见问题有一个已实现的解决方案。考虑使用ilen()来自的函数more_itertools

more_itertools.ilen(iterable)
Run Code Online (Sandbox Code Playgroud)

在文件中打印多行的示例(我们使用该with语句来安全地处理关闭文件):

# Example
import more_itertools

with open("foo.py", "r+") as f:
    print(more_itertools.ilen(f))

# Output: 433
Run Code Online (Sandbox Code Playgroud)

此示例返回的结果与前面介绍的对文件中的行进行总计的解决方案相同:

# Equivalent code
with open("foo.py", "r+") as f:
    print(sum(1 for line in f))

# Output: 433
Run Code Online (Sandbox Code Playgroud)