2012-01-19 18 views
197

Mam dwa istniejące słowniki i chcę "dołączyć" jeden z nich do drugiego. Rozumiem przez to, że klucz, wartości innego słownika powinien zostać wprowadzony do pierwszego słownika. Na przykład:Dołącz słownik do słownika?

orig = { 
    'A': 1, 
    'B': 2, 
    'C': 3, 
} 

extra = { 
    'D': 4, 
    'E': 5, 
} 

dest = # something here involving orig and extra 

print dest 
{ 
    'A': 1, 
    'B': 2, 
    'C': 3, 
    'D': 4, 
    'E': 5 
} 

myślę, że to wszystko można osiągnąć poprzez for pętli (może?), Ale jest tam jakiś sposób słowników lub inny moduł, który ratuje to zadanie dla mnie? Rzeczywiste słowniki Używam są naprawdę duże ...

+15

Kilka odpowiedzi wskazuje na 'orig.update (extra)' wykonuje zadanie. Zwróć uwagę, że jeśli 'extra' i' orig' mają nakładające się klawisze, ostateczna wartość zostanie pobrana z 'extra'. Na przykład: "d1 = {1: 1, 2: 2}; d2 = {2: 'ha!', 3: 3}; d1.update (d2) 'spowoduje, że' d1' zawiera '{1: 1, 2: 'ha!', 3: 3}'. –

Odpowiedz

310

Można zrobić

orig.update(extra) 

lub, jeśli nie chcesz orig być modyfikowane, zrobić pierwszy egzemplarz:

dest = dict(orig) # or orig.copy() 
dest.update(extra) 

pamiętać, że jeśli dodatkowo i oryg mieć klucze nakładających , ostateczna wartość zostanie pobrana z dodatkowego. Na przykład,

>>> d1 = {1: 1, 2: 2} 
>>> d2 = {2: 'ha!', 3: 3} 
>>> d1.update(d2) 
>>> d1 
{1: 1, 2: 'ha!', 3: 3} 
+2

Istnieje dict.copy(), który wykonuje płytkie kopie, takie jak metoda kopiowania. – sleeplessnerd

+0

Widziałem wcześniej ten idiom dict (** orig). Jaka jest przewaga nad dyktatem (orig)? – DSM

+2

Użycie 'dict (** orig)' utworzy nowy tymczasowy dict, który jest używany jako argument słowa kluczowego dla konstruktora dict. Następnie konstruktor skopiuje wartości z tego argumentu do siebie. Tworzysz więc dodatkowy słownik z 'dict (** orig)'. Jest to marnotrawstwem, gdy słowniki są duże, tak jak w pierwotnym pytaniu. –

12

dict.update() wygląda jak będzie to robić co chcesz ...

>> orig.update(extra) 
>>> orig 
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4} 
>>> 

Być może, choć nie chcesz zaktualizować swoją oryginalną słownika , ale pracować na kopii:

>>> dest = orig.copy() 
>>> dest.update(extra) 
>>> orig 
{'A': 1, 'C': 3, 'B': 2} 
>>> dest 
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4} 
5

Istnieje() metoda .update :)

aktualizacja ([inne]) Zaktualizuj słownik parami klucz/wartość z innych, nadpisując istniejące klucze. Zwróć Brak.

zmiana() przyjmuje albo innego obiektu słownika lub Iterable par klucz/wartości (jak krotki lub innych iterables długości dwóch). Jeśli argumenty kluczowe są określone, słownik jest następnie aktualizowana te pary klucz/wartość: d.update (red = 1, blue = 2).

Zmieniono w wersji 2.4: Dozwolone argument być iterable kluczowych par/wartości i dozwolonych argumentów kluczowych.

20

Zakładając, że nie chcesz, aby zmienić orig, można też zrobić kopię i aktualizacji jak innych odpowiedzi, czy można stworzyć nowy słownik w jednym kroku, przekazując wszystkie elementy z obu słowników do konstruktora dict:

from itertools import chain 
dest = dict(chain(orig.items(), extra.items())) 

lub bez itertools:

dest = dict(list(orig.items()) + list(extra.items())) 

Należy pamiętać, że trzeba tylko zdać wynik items() do list() w Pythonie 3, na 2.x dict.items() już zwraca listę więc można po prostu zrobić dict(orig.items() + extra.items()).

Jako bardziej ogólnym przypadku użycia, że ​​masz większą listę dicts które chcesz połączyć w jeden dict, można zrobić coś takiego:

from itertools import chain 
dest = dict(chain.from_iterable(map(dict.items, list_of_dicts))) 
+1

Właściwie wolę ten, ponieważ można "zaktualizować" słownik w tym samym wyrażeniu, którego chcesz użyć jako parametru, np .: 'SomeClass (** dict (args.items() + {'special': a_value,}.items())) ' – carlosayam

5

Odpowiedź chcę dać to „używać collections.ChainMap”, ale właśnie odkrył, że został dodany tylko w Pythonie 3.3: https://docs.python.org/3.3/library/collections.html#chainmap-objects

można spróbować szopka klasę od źródła 3.3 mimo: http://hg.python.org/cpython/file/3.3/Lib/collections/init.py#l763

o to mniej cecha-full Python 2.x kompatybilny le wersja (ten sam autor): http://code.activestate.com/recipes/305268-chained-map-lookups/

Zamiast rozszerzania/nadpisywania jednego słownika innym przy użyciu polecenia dict.merge lub tworzenia dodatkowej kopii scalającej oba, tworzony jest łańcuch wyszukiwania, który wyszukuje oba w kolejności. Ponieważ nie powiela odwzorowań mapowanych, ChainMap używa bardzo mało pamięci i widzi późniejszą modyfikację dowolnego podmapowania. Ponieważ zamówienie ma znaczenie, możesz także użyć domyślnych ustawień łańcucha (np. Użytkownik prefs> config> env).

17

Najbardziej pythonic (i nieco szybciej) drogą do osiągnięcia tego celu jest:

dest = {**orig, **extra} 

Lub, w zależności od problemu do rozwiązania, może:

dest = {**orig, 'D': 4, 'E': 5} 
+2

Niestety nie działa dla 2.x (((tylko dla 3.x – madjardi

+1

dict (itertools.chain (d.items(), y.items())) – madjardi

+0

Obie wersje właśnie dają mi błąd składni w 3.x IDLE – Noumenon

0

A trzy-liner połączyć lub scalić dwa słowniki:

dest = {} 
dest.update(orig) 
dest.update(extra) 

ta tworzy nowy słownik dest witho ut modyfikujące orig i extra.

Uwaga: jeśli klucz ma inne wartości w orig i extra, to extra zastępuje orig.

+0

Działa zarówno w Pythonie 2, jak i Pythonie 3. – jkdev