Количество строк в csv.DictReader - PullRequest
25 голосов
/ 23 мая 2010

У меня есть объект 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, если это возможно.

Любая помощь будет оценена.

Alan

Ответы [ 3 ]

29 голосов
/ 23 мая 2010
rows = list(myreader)
totalrows = len(rows)
for i, row in enumerate(rows):
    print("Row %d/%d" % (i+1, totalrows))
15 голосов
/ 23 мая 2010

Вам нужно открыть файл только один раз:

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() на объекте file в цикле и просто сообщить, через какой% данных вы прошли. Это будет немного неровно, но есть вероятность, что для любого файла, который достаточно велик, чтобы гарантировать наличие индикатора выполнения, отклонение длины записи будет потеряно из-за шума.

2 голосов
/ 23 мая 2010

Я не могу найти, как скопировать итератор.

Ближайшим является itertools.tee , но просто сделать из него list, как предполагает @ J.F.Sebastian, здесь лучше, как объясняют документы itertools.tee:

Этот itertool может потребовать значительного вспомогательное хранилище (в зависимости от того, как много временных данных должно быть сохранены). В общем, если один итератор использует большинство или все данные, прежде чем другой итератор запускается, он быстрее использовать list() вместо tee().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...