2012-01-25 14 views
28

Qual è il modo migliore per prendere un file di dati che contiene una riga di intestazione e leggere questa riga in una tupla denominata in modo che le righe di dati siano accessibili dal nome dell'intestazione?Qual è il modo pietonico per leggere i dati del file CSV come file di namedtuples?

stavo cercando qualcosa di simile:

import csv 
from collections import namedtuple 

with open('data_file.txt', mode="r") as infile: 
    reader = csv.reader(infile) 
    Data = namedtuple("Data", ", ".join(i for i in reader[0])) 
    next(reader) 
    for row in reader: 
     data = Data(*row) 

Il lettore oggetto non è subscriptable, in modo che il codice di cui sopra tiri un TypeError. Qual è il modo pietonico per leggere l'intestazione di un file in un namedtuple?

risposta

31

Usa:

Data = namedtuple("Data", next(reader)) 

e omettere la linea:

next(reader) 

Combinando questo con una versione iterativa basata sul commento di Martineau di seguito, l'esempio diventa per Python 2

import csv 
from collections import namedtuple 
from itertools import imap 

with open("data_file.txt", mode="rb") as infile: 
    reader = csv.reader(infile) 
    Data = namedtuple("Data", next(reader)) # get names from column headers 
    for data in imap(Data._make, reader): 
     print data.foo 
     # ...further processing of a line... 

e per Python 3

import csv 
from collections import namedtuple 

with open("data_file.txt", newline="") as infile: 
    reader = csv.reader(infile) 
    Data = namedtuple("Data", next(reader)) # get names from column headers 
    for data in map(Data._make, reader): 
     print(data.foo) 
     # ...further processing of a line... 
+1

drbunsen: Dopo aver fatto questo si può cambiare ciclo di elaborazione di : 'per i dati nella mappa (Data._make, reader):'. – martineau

+0

@spinup: ho modificato un po 'la tua modifica. – martineau

+0

Cosa succede se i dati CSV mancano di un'intestazione? C'è un modo per assegnare un nome a una colonna? (Se i dati CSV mancano di un'intestazione con nome e si desidera assegnare i nomi di colonna, mi sembra che la mia unica opzione sia quella di leggerlo come una sequenza di dizionari). –

20

Si prega di dare un'occhiata a csv.DictReader. Fondamentalmente, fornisce la possibilità di ottenere i nomi delle colonne dalla prima riga che stai cercando e, successivamente, ti consente di accedere a ciascuna colonna di una riga per nome usando un dizionario.

Se per qualche ragione è ancora necessario per accedere alle righe come un collections.namedtuple, dovrebbe essere facile per trasformare i dizionari di tuple denominati come segue:

with open('data_file.txt') as infile: 
    reader = csv.DictReader(infile) 
    Data = collections.namedtuple('Data', reader.fieldnames) 
    tuples = [Data(**row) for row in reader] 
+2

Il problema con questa soluzione è che ogni riga viene convertita in un dizionario e quindi convertita nella tupla denominata. Inefficiente se il dizionario intermedio non è richiesto. –

+0

Questo non mantiene l'ordine, quindi la prima colonna nel tuo csv diventa casuale nella tua namedtuple. A quel punto, potrebbe anche usare un ditt. – hraban

Problemi correlati