Подтвердить что ты не робот

Количество строк в csv.DictReader

У меня есть объект 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))

Я знаю, что могу получить общее количество, повторяя через читателя, но тогда я не смог запустить цикл "за". Я мог перебирать копию читателя, но я не могу найти, как копировать итератор.

Я мог бы также использовать

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

но это кажется ненужным повторным открытием файла. Я предпочел бы получить счетчик из DictReader, если это возможно.

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

Алан

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

Ближайший itertools.tee, но просто делая list этого, как предлагает @JFSebastian, лучше всего здесь, так как itertools.tee docs объясняет:

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