例如,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__自己并在某处保留元素数.
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)
该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中循环得到相当大的加速.
绝对不是,原因很简单,因为不能保证迭代是有限的.
考虑这个完全合法的生成函数:
def forever():
while True:
yield "I will run forever"
Run Code Online (Sandbox Code Playgroud)
尝试计算此功能的长度len([x for x in forever()])显然不起作用.
正如您所指出的,迭代器/生成器的大部分用途是能够处理大型数据集而无需将其全部加载到内存中.您不能立即获得长度的事实应被视为权衡.
事实证明,这个常见问题有一个已实现的解决方案。考虑使用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)