2015-04-10 22 views
5

Ich versuche, einige bestimmte Zeilen einer großen CSV-Datei zu lesen, und ich möchte nicht die gesamte Datei in den Speicher laden. Der Index der spezifischen Zeilen werden in einer Liste angegeben L = [2, 5, 15, 98, ...] und meine CSV-Datei sieht wie folgt aus:So lesen Sie bestimmte Zeilen einer großen CSV-Datei

Col 1, Col 2, Col3 
row11, row12, row13 
row21, row22, row23 
row31, row32, row33 
... 

die Ideen Mit here erwähnte ich den folgenden Befehl verwenden, um die Zeilen

with open('~/file.csv') as f: 
    r = csv.DictReader(f) # I need to read it as a dictionary for my purpose 

    for i in L: 
     for row in enumerate(r): 
      print row[i] 

ich sofort zu lesen erhalten den folgenden Fehler:

IndexError        Traceback (most recent call last) 
<ipython-input-25-78951a0d4937> in <module>() 
     6  for i in L: 
     7   for row in enumerate(r): 
----> 8    print row[i] 
IndexError: tuple index out of range 

Frage 1. Es ist wie meine Verwendung derscheintSchleifen ist hier offensichtlich falsch. Irgendwelche Ideen, wie das zu beheben ist?

Auf der anderen Seite erhält die folgenden den Job zu erledigen, aber es ist zu langsam:

def read_csv_line(line_number): 
    with open("~/file.csv") as f: 
     r = csv.DictReader(f) 
     for i, line in enumerate(r): 
      if i == (line_number - 2): 
       return line 
    return None 

for i in L: 
    print read_csv_line(i) 

Frage 2. Jede Idee, wie man durch die ganze Datei zu gehen, bis ich diese grundlegende Methode zur Verbesserung des Zeile erreichen, dann drucke ich es?

Antwort

5

Eine Datei nicht „Linien“ oder „Reihen“ haben. Was Sie als "Linie" betrachten, ist "Was ist zwischen zwei Newline Zeichen" gefunden. Daher können Sie die n-te Zeile nicht lesen, ohne vorher die Zeilen gelesen zu haben, da Sie die Zeilenumbruchzeichen nicht zählen konnten.

Antwort 1: Wenn Sie Ihr Beispiel betrachten, aber mit L = [9], würde Loops Abrollen:

i=9 
row = (0, {'Col 2': 'row12', 'Col 3': 'row13', 'Col 1': 'row11'}) 

Wie Sie sehen können, Zeile ist ein Tupel mit zwei Mitgliedern, ruft row[i] bedeutet row[9], daher der IndexError.

Antwort 2: Dies ist sehr langsam, weil Sie die Datei jedes Mal bis zur Zeilennummer lesen. In deinem Beispiel liest du die ersten 2 Zeilen, dann die ersten 5, dann die ersten 15, dann die ersten 98 usw. Also hast du die ersten 5 Zeilen 3 mal gelesen. Sie könnten einen Generator erstellen, die nur die Zeilen zurück, die Sie wollen (Vorsicht, Zeilennummern würden 0-indiziert werden):

def read_my_lines(csv_reader, lines_list): 
    for line_number, row in enumerate(csv_reader): 
     if line_number in lines_list: 
      yield line_number, row 

Also, wenn Sie die Zeilen bearbeiten möchten, würden Sie tun:

L = [2, 5, 15, 98, ...] 
with open('~/file.csv') as f: 
    r = csv.DictReader(f) 
    for line_number, line in read_my_lines(r, L): 
     do_something_with_line(line) 

* bearbeiten *

Dieses weiter verbessert werden könnte das lesen der Datei zu stoppen, wenn Sie alle Zeilen gelesen haben, Sie wollten:

2
for row in enumerate(r): 

wird Tupel ziehen. Sie versuchen dann, Ihr i-tes Element aus einem 2-Element-Tupel auszuwählen.

zum Beispiel

>> for i in enumerate({"a":1, "b":2}): print i 
(0, 'a') 
(1, 'b') 

Da außerdem Wörterbücher Hash-Tabellen sind, Ihre Erstbestellung ist nicht unbedingt erhalten. zum Beispiel:

>>list({"a":1, "b":2, "c":3, "d":5}) 
['a', 'c', 'b', 'd'] 
2

L Unter der Annahme ist eine Liste mit den Zeilennummern enthält, die Sie möchten, können Sie tun:

with open("~/file.csv") as f: 
    r = csv.DictReader(f) 
    for i, line in enumerate(r): 
     if i in L: # or (i+2) in L: from your second example 
      print line 

auf diese Weise:

  • Sie die Datei lesen nur einmal
  • Sie laden nicht die ganze Datei im Speicher
  • Sie erhalten nur die lin es sind Sie interessiert

Die einzige Einschränkung ist, dass Sie ganze Datei zu lesen, auch wenn L = [3]

+0

Danke, endlich habe ich etwas ähnliches getan. Der Haken war, dass meine Liste L bereits bestellt war und ich nicht wirklich jedes Mal die Mitgliedschaft überprüfen musste. Ich habe nur überprüft, ob 'i == L [0]', und dann den ersten Eintrag von 'L' weggelassen. Um das Lesen der ganzen Datei zu vermeiden, hat @vlad oben eine Lösung gefunden. – Keivan

1

Um die großartigen Ideen zusammenzufassen, habe ich am Ende so etwas verwendet: L kann relativ schnell sortiert werden, und in meinem Fall wurde es tatsächlich schon sortiert. Anstatt also mehrere Mitgliedsprüfungen in L durchzuführen, lohnt es sich, sie zu sortieren und dann nur jeden Index auf seinen ersten Eintrag zu prüfen. Hier ist mein Stück Code:

count=0 
with open('~/file.csv') as f: 
    r = csv.DictReader(f) 
    for row in r: 
     count += 1 
     if L == []: 
      break 
     elif count == L[0]: 
      print (row) 
      L.pop(0) 

Beachten Sie, dass diese stoppt, sobald wir durch L einmal gegangen sind.

Verwandte Themen