2008-12-24 66 views
34

例如,Python中的文件是可迭代的 - 它们迭代文件中的行。我想要统计行数。是否有任何内置的方式来获取python中的迭代长度?

一个快速的方法是做到这一点:

lines = len(list(open(fname))) 

然而,这种加载整个文件到内存中(一次)。这相当于破坏了迭代器的目的(它只需要将当前行保留在内存中)。

这不起作用:

lines = len(line for line in open(fname)) 

如发电机不具有的长度。

有没有办法做到这一点,定义一个计数函数?编辑:澄清,我明白,整个文件将不得不阅读!我只是不希望它在内存中一次=)。

+0

来计算您将在内存中加载文件的行数! – hasen 2008-12-24 06:00:29

+0

列表(所有序列类型)也是可迭代的。你的意思是“迭代器” – hop 2008-12-24 07:09:49

+4

@hasen:是的,但不是一次全部。 – Claudiu 2008-12-24 07:52:26

回答

53

短通过迭代迭代和重复计数,数没有。这就是使它成为可迭代的而不是列表的原因。这甚至不是一个特定于python的问题。看看传统的链表数据结构。查找长度是一个O(n)操作,它涉及迭代整个列表以查找元素的数量。

正如mcrute上面提到的,你或许可以减少你的函数:

def count_iterable(i): 
    return sum(1 for e in i) 

当然,如果你定义你自己的迭代对象可以随时实现__len__好自己,保持一个元素计数的地方。

+0

这可以通过itertools.tee() – hop 2008-12-25 20:16:53

+0

@hop改进:小心解释一下? – 2011-04-18 14:00:44

18

如果需要行的计数,你可以做到这一点,我不知道有什么更好的方式来做到这一点:

line_count = sum(1 for line in open("yourfile.txt")) 
0

如果你仔细想想,我们会怎么建议你找到一个文件中的行数而不读取整个文件的换行符?当然,你可以找到文件的大小,如果你可以保证一行的长度是x,你可以得到一个文件中的行数。但是,除非你有某种限制,否则我不会看到这是如何工作的。另外,因为iterables可以是无限长的...

7

绝对不是,因为iterables不能保证是有限的。

考虑这个完全合法发生器功能:

def forever(): 
    while True: 
     yield "I will run forever" 

试图计算此函数的长度与len([x for x in forever()])显然行不通。

正如您所指出的,迭代器/生成器的大部分目的是能够处理大型数据集而无需将其全部加载到内存中。你无法立即获得长度的事实应该被认为是一种折衷。

8

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

def len(thingy): 
    try: 
     return thingy.__len__() 
    except AttributeError: 
     return sum(1 for item in iter(thingy)) 
5

cardinality包提供了一个高效count()功能和一些相关的功能,计数和检查可迭代的大小:http://cardinality.readthedocs.org/

import cardinality 

it = some_iterable(...) 
print(cardinality.count(it)) 

它在内部使用enumerate()collections.deque()将所有实际的循环和计数逻辑移动到C级,导致相对于for在Python中循环。

2

事实证明,这个common problem实施的解决方案。考虑使用more_itertools中的ilen()函数。

more_itertools.ilen(iterable) 

打印文件中的行数(我们使用的with上下文管理器安全地处理关闭文件)的一个例子:

# Example 
import more_itertools 

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

# Output: 433 

此示例返回相同的结果早些时候提出的解决方案共线在一个文件中:

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

# Output: 433 
0

我没有在我的一些代码,发现关于正多少图的两种常见方法之间的测试顶点有,看看生成列表中哪些计数元素的方法变得更快。 Sage有一个生成器图(n),它生成n个顶点上的所有图。我创建了两个函数,它们以两种不同的方式获取迭代器获得的列表长度,并使用time.time()函数为每个函数计时(平均超过100次测试运行)。的功能如下:

def test_code_list(n): 
    l = graphs(n) 
    return len(list(l)) 

def test_code_sum(n): 
    S = sum(1 for _ in graphs(n)) 
    return S 

现在我时间每个方法

import time 

t0 = time.time() 
for i in range(100): 
    test_code_list(5) 
t1 = time.time() 

avg_time = (t1-t0)/10 

print 'average list method time = %s' % avg_time 


t0 = time.time() 
for i in range(100): 
    test_code_sum(5) 
t1 = time.time() 

avg_time = (t1-t0)/100 

print "average sum method time = %s" % avg_time 

平均列表方法时间= 0.0391882109642

平均总和方法时间= 0.0418473792076

因此,通过这种方式计算n = 5个顶点上的图的数量,列表方法稍微快一点(尽管100次测试运行不是很好的样本大小)。但是,当我增加了列表的长度由上N = 7个顶点试图图形计算(即改变的曲线图(5)〜图(7)),其结果是这样的:

平均列表方法时间= 4.14753051996

平均求和方法时间= 3.96504004002

在这种情况下,求和方法稍快。总而言之,这两种方法的速度大致相同,但差异可能取决于列表的长度(也可能仅仅是我平均超过100次测试运行,这并不是很高 - 会花费很长时间除此以外)。

相关问题