csv.DictReader中的行数

时间:2010-05-23 03:03:08

标签: python iterator python-3.x

我有一个csv DictReader对象(使用Python 3.1),但是我想知道之前中包含的行数/行数迭代它。如下所示...

myreader = csv.DictReader(open('myFile.csv', newline=''))

totalrows = ?

rowcount = 0
for row in myreader:
    rowcount +=1
    print("Row %d/%d" % (rowcount,totalrows))

我知道我可以通过迭代读取器来获得总数,但之后我无法运行'for'循环。我可以遍历阅读器的副本,但我找不到如何复制迭代器。

我也可以使用

totalrows = len(open('myFile.csv').readlines())

但这似乎是不必要的重新打开文件。如果可能的话,我宁愿从DictReader获取计数。

任何帮助都将不胜感激。

艾伦

4 个答案:

答案 0 :(得分:28)

rows = list(myreader)
totalrows = len(rows)
for i, row in enumerate(rows):
    print("Row %d/%d" % (i+1, totalrows))

答案 1 :(得分:15)

您只需要打开一次文件:

import csv

f = open('myFile.csv', 'rb')

countrdr = csv.DictReader(f)
totalrows = 0
for row in countrdr:
  totalrows += 1

f.seek(0)  # You may not have to do this, I didn't check to see if DictReader did

myreader = csv.DictReader(f)
for row in myreader:
  do_work

无论你做什么,你都要做两次通过(好吧,如果你的记录是一个固定的长度 - 这是不太可能的 - 你可以得到文件大小和除法,但我们假设不是这种情况)。再次打开文件确实不会花费太多,但您可以避免它,如此处所示。转换为仅使用len()的列表可能会浪费大量内存,而且不会更快。

注意:“Pythonic”方式是使用enumerate而不是+=,但UNPACK_TUPLE操作码非常昂贵,使得enumerate比增加本地速度慢。话虽这么说,你可能应该避免不必要的微观优化。

更多备注:如果您真的只想生成某种进度指示器,则不一定必须基于记录。您可以在循环中的文件对象上tell(),只报告您通过的数据百分比。它会有点不平衡,但是任何大到足以保证记录长度偏差的文件都有可能在噪音中丢失。

答案 2 :(得分:2)

  

我找不到如何复制   迭代器。

最近的是itertools.tee,但正如@ J.F.Sebastian建议的那样,简单地制作一个list就是最好的,正如itertools.tee的文档所解释的那样:

  

这个itertool可能需要很多   辅助存储(取决于如何   需要很多临时数据   存储)。一般来说,如果一个迭代器   之前使用大部分或全部数据   另一个迭代器启动,它更快   使用list()代替tee()

答案 3 :(得分:0)

如答案https://stackoverflow.com/a/2890569/8056572中所述,您可以通过将阅读器的长度转换为列表来获得行数。但是,这将对RAM消耗产生影响,并且您将失去读取器(它是一个生成器)的好处。

我认为最好的解决方案是将文件打开两次:

  1. 计算行数:
total_rows = sum(1 for _ in open('myFile.csv')) # -1 if you want to remove the header from the count

注意:我没有使用.readlines()来避免将所有行加载到内存中

  1. 反复重申

根据您的代码段,您将得到以下内容:

import csv

totalrows = sum(1 for _ in open('myFile.csv'))

myreader = csv.DictReader(open('myFile.csv'))

for i, _ in enumerate(myreader, start=1):
    print("Row %d/%d" % (i, totalrows))

注意:start=1中的enumerate表示i的第一个值。默认情况下为0,如果保留此默认值,则必须在打印语句中使用i + 1


如果您确实不想两次打开文件,则可以按照答案https://stackoverflow.com/a/2891061/8056572中所述使用seek

import csv

f = open('myFile.csv')

total_rows = sum(1 for _ in f)

f.seek(0)

myreader = csv.DictReader(f)

for i, _ in enumerate(myreader, start=1):
    print("Row %d/%d" % (i, totalrows))