2015-04-01 8 views
5

Próbuję zapisać zagnieżdżony słownik do pliku .csv. Oto prosty przykład:Python: Pisanie zagnieżdżonego słownika do 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]]) 

To dostaje mi stolik z dwoma kolumnami: pierwsza zawiera orgname; drugi zawiera [2, 1, 1] (lub odpowiednie wartości z pod-słownika). Chciałbym tabelę z czterema kolumnami: jedną dla orgname, a następnie trzy dla odpowiednich elementów listy.

+0

Dicts nie mają porządku, więc masz kłopoty od razu –

+0

@PadraicCunningham zgodził. Jednak jego klucze wydają się być zgodne z porządkiem leksykograficznym. Tak więc mógł nadal działać, sortując dw.keys(), a następnie iterując nad tym. –

Odpowiedz

3

Zmiana:

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

Do:

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

przeciwnym razie postaram się napisać coś podobnego [orgname1, [2, 1, 1]] do csv, a to znaczy [orgname1, 2, 1, 1].

Jak wspomniał Padraic, możesz chcieć zmienić years = dw.values()[0].keys() na years = sorted(dw.values()[0].keys()) lub years = fields[1:], aby uniknąć przypadkowego zachowania.

+0

nie trzeba sortować lat, jeśli używałbyś DictWriter, jak sugerowano w innych odpowiedziach –

+0

@heereereperoftware Tak, ale to byłoby właśnie teraz kopiowanie. – matsjoyce

8

To wygląda na zadanie dla 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

Zasługujesz na najlepszy komentarz, ponieważ jesteś pierwszym kompletnym rozwiązaniem i podoba mi się sposób, w jaki korzystałeś z funkcji aktualizacji Dicts. dostosowałem to w mojej odpowiedzi w oddzielnej funkcji, aby zachować ją jako jedną linijkę później. więc moja odpowiedź jest prawie Twoja, zmieniona na plik wyjściowy i dodane nagłówki :) –

5

Alternative realizacji z wykorzystaniem DictWriter oraz z nagłówkami

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}) 

wyjściowa:

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

Najbardziej lubię twoją odpowiedź, prosto :) możesz rozważyć sortowanie 'dw' za pomocą swoich kluczy, ponieważ w twoim wyjściu kolejność orgnames zmieniła się z wkład. używanie 'sorted (dw.items())' naprawia ten –

+0

Drodzy użytkownicy Pythona 3, którzy nie chcą się zawstydzać spędzając wiele godzin na tym, co właśnie zrobiłem, kiedy wszystko co musisz zrobić, to po prostu zmienić 'open (" test_output.csv "," wb ")' dla 'open (" test_output.csv "," w ", newline = '')' i powyższe rozwiązanie będzie działać bezbłędnie. Otrzymasz obiekt typu "bajtopodobny", a nie "str" ​​podczas zapisywania do pliku "inaczej". Nie bądź nana i spróbuj zakodować cały słownik na "ascii" tak jak ja. – Frikster

1

Korzystanie DictWriter nie ma potrzeby w sortowaniu pola z wyprzedzeniem, od w.writerow() zapewni prawidłową kolejność. Ale sens ma samo sortowanie przedmiotów.

więc łącząc wszystkie powyższe sugestie i zbieranie najlepszych każdy, chciałbym wymyślić następujący kod:

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)) 

dodałem niewielką mergedict() funkcję, która sprawia, że ​​jest to jeden liner dalej.