Python dyktuje, jak utworzyć klucz lub dołączyć element do klucza?

161

Mam pusty słownik. Nazwa: dict_x ma mieć klucze, których wartości są listami.

Z oddzielnej iteracji otrzymuję klucz (np .:) key_123i element (krotkę) do umieszczenia na liście dict_xwartości key_123.

Jeśli ten klucz już istnieje, chcę dołączyć ten element. Jeśli ten klucz nie istnieje, chcę go utworzyć z pustą listą, a następnie dołączyć do niego lub po prostu utworzyć go z krotką.

W przyszłości, gdy ponownie pojawi się ten klucz, ponieważ istnieje, chcę, aby wartość została ponownie dodana.

Mój kod składa się z tego:

Uzyskaj klucz i wartość.

Sprawdź, czy klucz NIE istnieje w dict_x.

a jeśli nie, utwórz go: dict_x[key] == []

Potem: dict_x[key].append(value)

Czy to jest sposób na zrobienie tego? Czy mam spróbować użyć try/exceptklocków?

Phil
źródło

Odpowiedzi:

253

Zastosowanie dict.setdefault():

dic.setdefault(key,[]).append(value)

help (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
Ashwini Chaudhary
źródło
4
Robiłem to, dict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]ale ta odpowiedź sugeruje znacznie lepszy sposób. W rzeczywistości jest set()to argument i pozwala na użycie add()metody ...
fatih_dur
66

Oto różne sposoby, aby to zrobić, aby porównać jego wygląd i wybrać to, co lubisz. Zamówiłem je w sposób, który moim zdaniem jest najbardziej „pytoniczny” , i skomentowałem zalety i wady, które mogą nie być oczywiste na pierwszy rzut oka:

Używając collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

Plusy: Prawdopodobnie najlepsza wydajność. Wady: Niedostępne w Pythonie 2.4.x.

Używając dict().setdefault():

dict_x = {}

...

dict_x.setdefault(key, []).append(value)

Wady: nieefektywne tworzenie nieużywanych list()s.

Używając try ... except:

dict_x = {}

...

try:
    values = dict_x[key]
except KeyError:
    values = dict_x[key] = []
values.append(value)

Lub:

try:
    dict_x[key].append(value)
except KeyError:
    dict_x[key] = [value]
antak
źródło
Witaj, jak myślisz, dlaczego .setdefault tworzy niepotrzebne słowniki?
Phil
2
Nie sądzę, żeby .setdefault()tworzyło niepotrzebne słowniki. Myślę , że tworzę niepotrzebne lists (tj. []) W drugim argumencie, .setdefault()który nigdy nie jest używany, jeśli keyjuż istnieje. Mógłbym użyć dict.setdefault()(na korzyść wydajnego haszowania klucza) i użyć zmiennej do ponownego użycia nieużywanych lists, ale dodaje to kilka dodatkowych wierszy kodu.
antak
1
IIRC, w Pythonie pusta lista w równości jest uważana za stałą na poziomie kodu bajtowego, ale wymaga to potwierdzenia przez guru kodu bajtowego (lub po prostu użyj modułu disas).
gaborous
Korzystanie .setdefaulttworzy regularny dictgdzie klucz nieobecny look-up spowoduje KeyErrorwyciągnięcie collections.defaultdict(list)tworzy dictgdzie nieobecne kluczowych wyszukiwań wstawi pusta list- myślę, że należy wybrać na podstawie których zachowanie chcesz
Chris_Rands
Próbowałem czegoś podobnego do collections.defaultdict we własnym kodzie i miało to nieoczekiwane efekty uboczne. Weźmy na przykład następującą wymianę IDLE: >>> list_dict = defaultdict (list) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 Wygląda na to, że gdy Python wywołuje wartość domyślna dodaje klucz do słownika bez aktywnego ustawiania go, co spowoduje utworzenie wielu pustych list, jeśli wartość domyślna jest często używana. Zamierzam wprowadzić własne funkcje opakowujące dla słownika, nieefektywne, ale miejmy nadzieję, bardziej przewidywalne.
RDBury
26

Możesz użyć do tego domyślnego słowa .

from collections import defaultdict
d = defaultdict(list)
d['key'].append('mykey')

Jest to nieco bardziej wydajne niż wtedy setdefault, gdy nie tworzysz nowych list, których nie używasz. Każde wywołanie spowoduje setdefaultutworzenie nowej listy, nawet jeśli pozycja już istnieje w słowniku.

Nathan Villaescusa
źródło
14

Możesz użyć defaultdict w collections.

Przykład z doc:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
iMom0
źródło
0
dictionary['key'] = dictionary.get('key', []) + list_to_append
Tomas Silva Ebensperger
źródło
1
Powinieneś wyjaśnić (bardzo niewielką) korzyść, jaką ma to w obecności pewnych wyjątków; jako zwykły kod, nie jest jasne, dlaczego potrzebna jest dodatkowa odpowiedź.
Davis Herring
Cześć, tylko alternatywa bez dodatkowego importu. Można to oczywiście zrobić za pomocą instrukcji if. Po prostu proponuję alternatywę wykorzystującą moc .get () zamiast używania dict [].
Tomas Silva Ebensperger
Dwie pierwsze odpowiedzi wymieniają dwa różne sposoby bez importu (chociaż nie dict.get).
Davis Herring