2010-05-23 21 views
18

Tengo un objeto csv DictReader (usando Python 3.1), pero me gustaría saber el número de líneas/filas contenidas en el lector antes de I iterate through it. Algo así como de la siguiente manera ...Número de líneas en csv.DictReader

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

totalrows = ? 

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

Sé que podría obtener el total por iteración a través del lector, pero entonces yo no podía correr el bucle 'para'. Pude iterar a través de una copia del lector, pero no puedo encontrar cómo copiar un iterador.

También podría utilizar

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

pero que parece una reapertura innecesaria del archivo. Prefiero obtener el recuento de DictReader si es posible.

Cualquier ayuda sería apreciada.

Alan

Respuesta

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

Buena solución - Soy bastante nuevo con la idea de los iteradores, así que realmente no había apreciado enumerar() hasta ahora. Saludos. –

+7

Solo tenga cuidado con el tamaño de su conjunto de datos aquí. Convertir su lector en una lista podría tomar GOBS de memoria. –

+1

Esto cargará todos los datos en la memoria, contar líneas -1 es soluciones muy buenas –

2

no puedo encontrar la forma de copiar un iterador .

más cercano es itertools.tee, sino simplemente hacer una list de ella, como sugiere @JFSebastian, es mejor que aquí, como documentos de itertools.tee explican:

Este itertool pueden requerir significativa almacenamiento auxiliar (dependiendo de cómo se tengan que almacenar muchos datos temporales ). En general, si un iterador utiliza la mayoría o todos los datos antes de se inicia otro iterador, es más rápido para usar list() en lugar de tee().

+0

Todavía tiene el consumo de recursos potencialmente masivo con cualquier método. –

+0

Gracias Alex - listarlo es entonces. –

12

Sólo tiene que abrir el archivo una vez:

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 

No importa lo que usted tiene que hacer dos pases (así, si sus registros son una longitud fija - que es poco probable - que podría solo obtenga el tamaño del archivo y divídalo, pero supongamos que no es el caso). Abrir nuevamente el archivo realmente no le cuesta mucho, pero puede evitarlo como se ilustra aquí. La conversión a una lista solo para usar len() posiblemente desperdiciará toneladas de memoria y no será más rápida.

Nota: La forma 'Pythonic' es utilizar enumerate en lugar de +=, pero el código de operación UNPACK_TUPLE es tan caro que hace más lento que enumerate incremento de un local. Dicho esto, es probable que sea una micro-optimización innecesaria que probablemente debería evitar.

Más Notas: Si realmente desea generar algún tipo de indicador de progreso, no necesariamente tiene que estar basado en registros. Puede tell() en el objeto de archivo en el ciclo y simplemente informar qué% de los datos está pasando. Será un poco irregular, pero es probable que en cualquier archivo que sea lo suficientemente grande como para garantizar una barra de progreso, la desviación en la longitud del registro se perderá en el ruido.

+0

Nick - gracias por la respuesta. Parece que mi evitación de volver a abrir el archivo no vale la pena el código adicional involucrado (la legibilidad es superior al rendimiento en este caso). Gracias por la sugerencia con respecto a la velocidad de enumerate(). Tell() también es nuevo para mí. Lo investigaré más a fondo. Saludos. –

+0

Solo problema con esto ... ¿y si usa un vapor? – Nick

+0

@Nick: no hay magia en el mundo; esto no es un problema, solo un hecho. –

Cuestiones relacionadas