Zapisywanie słownika do pliku csv z jedną linią na każdy klucz: wartość

92

Mam słownik:

mydict = {key1: value_a, key2: value_b, key3: value_c}

Chcę zapisać dane do pliku dict.csv, w tym stylu:

key1: value_a
key2: value_b
key3: value_c

Napisałem:

import csv
f = open('dict.csv','wb')
w = csv.DictWriter(f,mydict.keys())
w.writerow(mydict)
f.close()

Ale teraz mam wszystkie klucze w jednym wierszu i wszystkie wartości w następnym.

Kiedy uda mi się napisać taki plik, chcę również przeczytać go z powrotem do nowego słownika.

Aby wyjaśnić mój kod, słownik zawiera wartości i boole z textctrls i pól wyboru (używając wxpython). Chcę dodać przyciski „Zapisz ustawienia” i „Wczytaj ustawienia”. Zapis ustawień powinien zapisać słownik do pliku w wymieniony sposób (aby ułatwić użytkownikowi bezpośrednią edycję pliku csv), załadować ustawienia należy odczytać z pliku i zaktualizować textctrls i checkboxy.

user1106770
źródło
1
czy możesz podać lepszy przykład tego, co chcesz jako wynik? „styl”, który masz powyżej, nie jest plikiem CSV. szukasz key1, value_a [linebreak] key2, value_b [linebreak] key3, value_c?
tkone
Innym podejściem jest użycie repr()do wypisania dyktowania, a następnie oceny ciągu, gdy go czytasz. Spójrz na ten stary post SO, aby zapoznać się z dyskusjami na temat str()vs. repr(), a także dokumentacją .
Peter Rowell
Oprócz mojej odpowiedzi poniżej, jeśli wolisz coś bardziej wyrafinowanego niż zwykły plik CSV, możesz sprawdzić ConfigParsermoduł
Ricardo Cárdenes
3
To, co opisujesz, to typowy format CSV zapisany przez moduł csv. Jeśli napiszesz wiele dykt z tymi samymi kluczami, klucze są zapisywane tylko raz, w pierwszej linii, po jednej linii na dyktę dla odpowiednich wartości, we właściwej kolejności, aby wyrównać z kluczami w linii 1.
PaulMcG

Odpowiedzi:

186

DictWriterNie działa zgodnie z oczekiwaniami.

with open('dict.csv', 'w') as csv_file:  
    writer = csv.writer(csv_file)
    for key, value in mydict.items():
       writer.writerow([key, value])

Aby to przeczytać:

with open('dict.csv') as csv_file:
    reader = csv.reader(csv_file)
    mydict = dict(reader)

co jest dość zwarte, ale zakłada, że ​​nie musisz wykonywać żadnej konwersji typów podczas czytania

Ricardo Cárdenes
źródło
2
Mmh ... Właśnie zauważyłem, że potrzebujesz konkretnego formatu, który nie jest dokładnie podobny do CSV. Założono, że chcesz stylu CSV (tj. Wiersz na parę klucz-wartość), ponieważ używasz modułu CSV ...
Ricardo Cárdenes,
3
Lub ... jeśli podejście CSV jest dokładnie tym, czego chciałeś, ale wolisz ":" jako separator, po prostu dodaj delimiter=':'podczas tworzenia pisarza i czytelnika :)
Ricardo Cárdenes
2
Uwaga, powinieneś zamknąć plik pomiędzy zapisem a odczytem. Zobacz, co się stało w przypadku tego pytania / odpowiedzi: stackoverflow.com/a/38467563/235698
Mark Tolonen
1
@MarkTolonen z pewnością, użycie withbyłoby lepsze. Zmienię przykłady, aby to odzwierciedlić ...
Ricardo Cárdenes,
1
@DareYang przepraszam za opóźnienie. Właściwie nie jestem pewien, dlaczego wtedy to napisałem. To nie jest potrzebne. Podczas pisania skutkuje to pozostawieniem znaków nowej linii nieprzetłumaczonych (tj. Jeśli napiszesz \n, dostaniesz się \ndo pliku). Jeśli pozostawisz go samemu, włącza się „tryb uniwersalny” i znaki nowej linii są tłumaczone na domyślne dla bieżącego systemu operacyjnego. Biorąc pod uwagę, że nie jest to naprawdę przydatne (z wyjątkiem sytuacji, gdy chcesz mieć przewidywalne znaki nowej linii), usunę je.
Ricardo Cárdenes
27

Aby dać opcję, zapisanie słownika do pliku csv może być również wykonane za pomocą pakietu pandas. W podanym przykładzie mogłoby to wyglądać mniej więcej tak:

mydict = {'key1': 'a', 'key2': 'b', 'key3': 'c'}

import pandas as pd

(pd.DataFrame.from_dict(data=mydict, orient='index')
   .to_csv('dict_file.csv', header=False))

Najważniejszą rzeczą do wzięcia pod uwagę jest ustawienie parametru „orient” na „index” w metodzie from_dict . Dzięki temu możesz zdecydować, czy chcesz zapisywać każdy klucz słownika w nowym wierszu.

Dodatkowo w metodzie to_csv parametr nagłówka jest ustawiony na False, aby mieć tylko elementy słownika bez irytujących wierszy. Zawsze możesz ustawić nazwy kolumn i indeksów wewnątrz metody to_csv.

Twój wynik wyglądałby następująco:

key1,a
key2,b
key3,c

Jeśli zamiast tego chcesz, aby klucze były nazwami kolumn, po prostu użyj domyślnego parametru „orient”, czyli „kolumny”, co można sprawdzić w linkach do dokumentacji.

Ivan Calderon
źródło
2
Świetnie działało jak marzenie :). Moja wartość była listą i wygenerowała mój plik csv ze wszystkimi wartościami listy w wielu komórkach i zmapowany na klucz w pierwszej kolumnie.
vinsinraw
14

Najłatwiej jest zignorować moduł csv i samodzielnie go sformatować.

with open('my_file.csv', 'w') as f:
    [f.write('{0},{1}\n'.format(key, value)) for key, value in my_dict.items()]
Phil Horowitz
źródło
8
Jeśli pojawi się keyprzecinek, będziesz się źle bawić.
Ali Ashraf,
5
Uważam, że łatwiej jest po prostu używać csv.writer(...).writerows(my_dict.items()). csvModuł ma o wiele więcej niż tylko dodać przecinki i znaki nowej linii.
Martijn Pieters
6
outfile = open( 'dict.txt', 'w' )
for key, value in sorted( mydict.items() ):
    outfile.write( str(key) + '\t' + str(value) + '\n' )
FCAlive
źródło
1
Prosimy również o podanie pewnych informacji lub komentarzy do swojej odpowiedzi.
NDM,
2

Czy możesz po prostu zrobić:

for key in mydict.keys():
    f.write(str(key) + ":" + str(mydict[key]) + ",");

Abyś mógł

klucz_1: wartość_1, klucz_2: wartość_2

louis.luo
źródło
3
Byłoby lepiej ','.join("%s:%s" % (k,v) for k,v in mydict.items())- zwykle lepiej jest iterować po elementach dykta, które dają klucze i wartości razem, niż po kluczach dyktu i wyszukiwać wartości „n”. ','.join(...)dba o umieszczanie tylko przecinków między wartościami, bez dodawania dodatkowego końcowego przecinka.
PaulMcG
zauważ, że nie będziesz potrzebować średnika na końcu tego kodu Pythona
beep_check
1

Osobiście zawsze uważałem moduł csv za irytujący. Spodziewam się, że ktoś inny pokaże ci, jak to zręcznie zrobić, ale moje szybkie i brudne rozwiązanie to:

with open('dict.csv', 'w') as f:  # This creates the file object for the context 
                                  # below it and closes the file automatically
    l = []
    for k, v in mydict.iteritems(): # Iterate over items returning key, value tuples
        l.append('%s: %s' % (str(k), str(v))) # Build a nice list of strings
    f.write(', '.join(l))                     # Join that list of strings and write out

Jeśli jednak chcesz go ponownie przeczytać, musisz wykonać irytującą analizę, zwłaszcza jeśli wszystko jest w jednym wierszu. Oto przykład wykorzystujący proponowany format pliku.

with open('dict.csv', 'r') as f: # Again temporary file for reading
    d = {}
    l = f.read().split(',')      # Split using commas
    for i in l:
        values = i.split(': ')   # Split using ': '
        d[values[0]] = values[1] # Any type conversion will need to happen here
Griffith Rees
źródło
Poszedłbym z odpowiedzią Ricarda. Lub przynajmniej użyj oddzielnych linii.
Griffith Rees
0
import csv

dict = {"Key Header":"Value Header", "key1":"value1", "key2":"value2"}

with open("test.csv", "w") as f:
    writer = csv.writer(f)
    for i in dict:
      writer.writerow([i, dict[i]])
f.close() 

wprowadź opis obrazu tutaj

Apurva Thorat
źródło
Myślę, że nie musisz jawnie zamykać pliku w ostatniej linii. Menedżer kontekstu zrobi to za Ciebie.
avaj_wen12
0
#code to insert and read dictionary element from csv file
import csv
n=input("Enter I to insert or S to read : ")
if n=="I":
    m=int(input("Enter the number of data you want to insert: "))
    mydict={}
    list=[]
    for i in range(m):
        keys=int(input("Enter id :"))
        list.append(keys)
        values=input("Enter Name :")
        mydict[keys]=values

    with open('File1.csv',"w") as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=list)
        writer.writeheader()
        writer.writerow(mydict)
        print("Data Inserted")
else:
    keys=input("Enter Id to Search :")
    Id=str(keys)
    with open('File1.csv',"r") as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            print(row[Id]) #print(row) to display all data
Ashish Nandan
źródło
Byłoby lepiej, gdybyś dodał trochę wyjaśnienia
Roaim,
-2

Czy próbowałeś dodać „s” na: w w.writerow(mydict)ten sposób w.writerows(mydict):? Ten problem mi się przydarzył, ale w przypadku list użyłem liczby pojedynczej zamiast liczby mnogiej.

Hikhuj
źródło