web-dev-qa-db-fra.com

Nombre de lignes dans csv.DictReader

J'ai un objet csv DictReader (en utilisant Python 3.1), mais je voudrais connaître le nombre de lignes/lignes contenues dans le lecteur avant je le parcourt. Quelque chose comme suit ...

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

totalrows = ?

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

Je sais que je pourrais obtenir le total en itérant à travers le lecteur, mais je ne pouvais pas exécuter la boucle "for". Je pourrais parcourir une copie du lecteur, mais je ne trouve pas comment copier un itérateur.

Je pourrais aussi utiliser

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

mais cela semble une réouverture inutile du fichier. Je préfère obtenir le décompte du DictReader si possible.

Toute aide serait appréciée.

Alan

29
Alan Harris-Reid
rows = list(myreader)
totalrows = len(rows)
for i, row in enumerate(rows):
    print("Row %d/%d" % (i+1, totalrows))
33
jfs

Vous n'avez besoin d'ouvrir le fichier qu'une seule fois:

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

Peu importe ce que vous faites, vous devez effectuer deux passes (enfin, si vos enregistrements sont de longueur fixe - ce qui est peu probable - vous pouvez simplement obtenir la taille du fichier et la diviser, mais supposons que ce n'est pas le cas). Rouvrir le fichier ne vous coûte vraiment pas cher, mais vous pouvez l'éviter comme illustré ici. La conversion en une liste uniquement pour utiliser len() va potentiellement gaspiller des tonnes de mémoire, et ne sera pas plus rapide.

Remarque: La méthode 'Pythonic' consiste à utiliser enumerate au lieu de +=, Mais l'opcode UNPACK_Tuple Est si cher qu'il rend enumerate plus lent que l'incrémentation d'un local. Cela étant dit, il s'agit probablement d'une micro-optimisation inutile que vous devriez probablement éviter.

Plus de notes: Si vous voulez vraiment simplement générer une sorte d'indicateur de progression, il ne doit pas nécessairement être basé sur des enregistrements. Vous pouvez tell() sur l'objet fichier dans la boucle et simplement signaler le% des données que vous traversez. Ce sera un peu inégal, mais il y a des chances pour tout fichier suffisamment grand pour justifier une barre de progression que l'écart sur la longueur d'enregistrement sera perdu dans le bruit.

15
Nick Bastin

Je ne trouve pas comment copier un itérateur.

Le plus proche est itertools.tee , mais simplement en faire un list, comme le suggère @ J.F.Sebastian, est mieux ici, comme l'expliquent les documents d'itertools.tee:

Cet outil peut nécessiter un stockage auxiliaire important (selon la quantité de données temporaires à stocker). En général, si un itérateur utilise la plupart ou la totalité des données avant le démarrage d'un autre itérateur, il est plus rapide d'utiliser list() au lieu de tee().

2
Alex Martelli