2015-04-01 20 views
5

Sto provando a scrivere un dizionario nidificato in un file .csv. Ecco un semplice esempio:Python: scrittura del dizionario annidato in CSV

import csv 
import itertools 

fields = [ 'org', '2015', '2014', '2013' ] 
dw  = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 }, 
      'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 }, 
      'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 } 
     } 

with open("test_output.csv", "wb") as f: 
    w = csv.writer(f) 
    years = dw.values()[0].keys() 
    for key in dw.keys(): 
     w.writerow([key, [dw[key][year] for year in years]]) 

Questo mi fa una tabella con due colonne: la prima contiene orgname; il secondo contiene [2, 1, 1] (o i valori corrispondenti dal sottot dizionario). Mi piacerebbe un tavolo con quattro colonne: uno per orgname e poi tre per gli elementi di elenco corrispondenti.

+0

dts non hanno ordine quindi sei nei guai immediatamente –

+0

@PadraicCunningham concordato. Tuttavia, le sue chiavi sembrano seguire un ordine lessografico. Quindi, poteva ancora farlo funzionare ordinando dw.keys() e quindi iterando su quello. –

risposta

3

Cambio:

w.writerow([key, [dw[key][year] for year in years]]) 

A:

w.writerow([key] + [dw[key][year] for year in years]) 

In caso contrario, si tenta di scrivere qualcosa di simile [orgname1, [2, 1, 1]] al CSV, mentre vuoi dire [orgname1, 2, 1, 1].

Come indicato da Padraic, è possibile cambiare years = dw.values()[0].keys() a years = sorted(dw.values()[0].keys()) o years = fields[1:] per evitare comportamenti casuali.

+0

non è necessario ordinare gli anni, se si userebbe DictWriter come suggerito in altre Risposte –

+0

@hexereisoftware Sì, ma sarebbe solo copiato ora. – matsjoyce

8

Questo appare come un lavoro per DictWriter:

import csv 
import itertools 
import sys 

fields = [ 'org', '2015', '2014', '2013' ] 
dw  = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 }, 
      'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 }, 
      'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 } 
     } 

w = csv.DictWriter(sys.stdout, fields) 
for key,val in sorted(dw.items()): 
    row = {'org': key} 
    row.update(val) 
    w.writerow(row) 
+0

ti meriti il ​​miglior commento in realtà, perché sei la prima soluzione completa e mi piace il modo in cui hai usato la funzione di aggiornamento di dicts. l'ho adattato nella mia risposta in una funzione separata per mantenerlo un solo rivestimento in seguito. quindi la mia risposta è più o meno la tua, cambiata in output di file e intestazioni aggiunte :) –

5

implementazione alternativo utilizzando DictWriter e con le intestazioni

import csv 
import itertools 

fields = [ 'org', '2015', '2014', '2013' ] 
dw  = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 }, 
      'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 }, 
      'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 } 
     } 

with open("test_output.csv", "wb") as f: 
    w = csv.DictWriter(f, fields) 
    w.writeheader() 
    for k in dw: 
     w.writerow({field: dw[k].get(field) or k for field in fields}) 

uscita:

org,2015,2014,2013 
orgname1,2,1,1 
orgname3,1,3,1 
orgname2,1,2,3 
+0

mi piace la tua risposta migliore, diretta :) potresti prendere in considerazione l'ordinamento di 'dw' con le sue chiavi poiché nel tuo output l'ordine degli orgnames è cambiato da ingresso. usando 'sorted (dw.items())' corregge questo –

+0

Cari utenti Python 3 che non vogliono mettersi in imbarazzo dedicando ore a questo come ho appena fatto quando tutto ciò che dovete fare è semplicemente passare 'open (" test_output.csv "," wb ")' per 'open (" test_output.csv "," w ", newline = '')' e la soluzione sopra funzionerà perfettamente. Otterrai un oggetto simile a un byte e non "str" ​​quando scrivi su un file "altrimenti". Non essere un nana e prova a codificare il tuo intero dizionario in "ascii" come me. – Frikster

1

Utilizzando DictWriter non v'è alcuna necessità di smistamento i campi in anticipo, dal w.writerow() assicurerà l'ordine corretto. Ma ha senso per ordinare gli oggetti stessi.

Così mettendo insieme tutti i suggerimenti di cui sopra e raccogliendo il meglio di ciascuno, mi sarebbe venuto su con seguente codice:

import csv 
import itertools 

def mergedict(a,b): 
    a.update(b) 
    return a 

fields = [ 'org', '2015', '2014', '2013' ] 
dw  = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 }, 
      'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 }, 
      'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 } 
     } 

with open("test_output.csv", "wb") as f: 
    w = csv.DictWriter(f, fields) 
    w.writeheader() 
    for k,d in sorted(dw.items()): 
     w.writerow(mergedict({'org': k},d)) 

ho aggiunto un piccolo mergedict() funzione che lo rende un uno di linea più in basso.