Je dois accéder à la Nième ligne dans un fichier CSV.
Voici ce que j'ai fait:
import csv
the_file = open('path', 'r')
reader = csv.reader(the_file)
N = input('What line do you need? > ')
i = 0
for row in reader:
if i == N:
print("This is the line.")
print(row)
break
i += 1
the_file.close()
... mais cela ne semble pas optimal. Modifier pour plus de précision: si le fichier est volumineux, je ne veux pas parcourir toutes les lignes et je ne veux pas avoir à charger tout le fichier en mémoire.
J'espère quelque chose comme reader[N]
existe, mais je ne l'ai pas trouvé.
Modifier pour la réponse: Cette ligne (provenant de la réponse choisie) est ce que je cherchais:
next(itertools.islice(csv.reader(f), N, None)
Cela fait peu de différence mais il est légèrement plus propre d'utiliser enumerate
plutôt que de créer votre propre variable de compteur.
for i, row in enumerate(reader):
if i == N:
print("This is the line.")
print(row)
break
Vous pouvez aussi utiliser itertools.islice
qui est conçu pour ce type de scénario - accéder à une tranche particulière d'un itérable sans lire le tout en mémoire. Cela devrait être un peu plus efficace que de parcourir les lignes indésirables.
with open(path, 'r') as f:
N = int(input('What line do you need? > '))
print("This is the line.")
print(next(itertools.islice(csv.reader(f), N, None)))
Mais si votre fichier CSV est petit, lisez simplement le tout dans une liste, à laquelle vous pouvez ensuite accéder avec un index de la manière habituelle. Cela présente également l'avantage que vous pouvez accéder à plusieurs lignes différentes dans un ordre aléatoire sans avoir à réinitialiser le lecteur csv.
my_csv_data = list(reader)
print(my_csv_data[N])
Votre solution n'est en fait pas si mauvaise. Faire avancer l'itérateur de fichier jusqu'à la ligne souhaitée est une bonne approche et est utilisé dans de nombreuses situations comme celle-ci.
Si vous voulez que ce soit plus concis, vous pouvez utiliser next
et enumerate
avec un expression de générateur :
import csv
the_file = open('path', 'r')
reader = csv.reader(the_file)
N = int(input('What line do you need? > '))
line = next((x for i, x in enumerate(reader) if i == N), None)
print(line)
the_file.close()
Le None
dedans est ce qui sera retourné si la ligne n'est pas trouvée (N
est trop grande). Vous pouvez cependant choisir n'importe quelle autre valeur.
Vous pouvez également ouvrir le fichier avec un with-statement pour le fermer automatiquement:
import csv
with open('path', 'r') as the_file:
reader = csv.reader(the_file)
N = int(input('What line do you need? > '))
line = next((x for i, x in enumerate(reader) if i == N), None)
print(line)
Si vous voulez vraiment réduire la taille, vous pouvez faire:
from csv import reader
N = int(input('What line do you need? > '))
with open('path') as f:
print(next((x for i, x in enumerate(reader(f)) if i == N), None))
Vous pouvez simplement faire:
n = 2 # line to print
fd = open('foo.csv', 'r')
lines = fd.readlines()
print lines[n-1] # prints 2nd line
fd.close()
Ou encore mieux pour utiliser moins de mémoire en ne chargeant pas le fichier entier en mémoire:
import linecache
n = 2
linecache.getline('foo.csv', n)
Le module itertools
a un certain nombre de fonctions pour créer des itérateurs spécialisés - et sa fonction islice()
pourrait être utilisée pour résoudre facilement ce problème:
import csv
import itertools
N = 5 # desired line number
with open('path.csv', newline='') as the_file:
row = next(csv.reader(itertools.islice(the_file, N, N+1)))
print("This is the line.")
print(row)
P.S. Pour les curieux, ma réponse initiale - qui fonctionne aussi (sans doute mieux) - a été:
row = next(itertools.islice(csv.reader(the_file), N, N+1))
import csv
with open('cvs_file.csv', 'r') as inFile:
reader = csv.reader(inFile)
my_content = list(reader)
line_no = input('What line do you need(line number begins from 0)? > ')
if line_no < len(my_content):
print(my_content[line_no])
else:
print('This line does not exists')
En tant que result
, vous pouvez maintenant obtenir n'importe quelle ligne par son index
directly
:
What line do you need? > 2
['101', '0.19', '1']
What line do you need? > 100
This line does not exists
Vous pouvez minimiser votre boucle for
en une expression de compréhension, par exemple.
row = [row for i,row in enumerate(reader) if i == N][0]
# or even nicer as seen in iCodez code with next and generator expression
row = next(row for i,row in enumerate(reader) if i == N)