d3 = dict(d1, **d2)
Rozumiem, że powoduje to scalenie słownika. Ale czy jest wyjątkowy? A co jeśli d1 ma ten sam klucz co d2, ale inną wartość? Chciałbym, aby d1 i d2 zostały połączone, ale d1 ma priorytet, jeśli istnieje zduplikowany klucz.
python
dictionary
TIMEX
źródło
źródło
**
przekazywania argumentów słów kluczowych, chyba że wszystkie kluczed2
są ciągami. Jeśli nie wszystkie kluczed2
są ciągami znaków, nie powiedzie się to w Pythonie 3.2 oraz w alternatywnych implementacjach Pythona, takich jak Jython, IronPython i PyPy. Zobacz na przykład mail.python.org/pipermail/python-dev/2010-April/099459.html .Odpowiedzi:
Możesz użyć tej
.update()
metody, jeśli nie potrzebujesz już oryginałud2
:Na przykład:
>>> d1 = {'a': 1, 'b': 2} >>> d2 = {'b': 1, 'c': 3} >>> d2.update(d1) >>> d2 {'a': 1, 'c': 3, 'b': 2}
Aktualizacja:
Oczywiście możesz najpierw skopiować słownik, aby utworzyć nowy, scalony. Może to być konieczne lub nie. W przypadku, gdy w słowniku znajdują się obiekty złożone (obiekty, które zawierają inne obiekty, takie jak listy lub instancje klas),
copy.deepcopy
należy również wziąć pod uwagę.źródło
isinstance(int, object) is True
aledeepcopy
nie wydaje się to konieczne.W Pythonie2
d1={'a':1,'b':2} d2={'a':10,'c':3}
d1 zastępuje d2:
dict(d2,**d1) # {'a': 1, 'c': 3, 'b': 2}
d2 zastępuje d1:
dict(d1,**d2) # {'a': 10, 'c': 3, 'b': 2}
Takie zachowanie to nie tylko przypadek implementacji; w dokumentacji gwarantuje się :
źródło
**
notacją, wszystkie klucze tego dyktu powinny być ciągami. Zobacz wątek python-dev zaczynający się na mail.python.org/pipermail/python-dev/2010-April/099427.html, aby uzyskać więcej informacji.d = dict(**d1, **d2)
działa, ale do tego odwołuje się @IoannisFilippidis w swoim komentarzu. Być może włączenie tutaj fragmentu byłoby jaśniejsze, więc oto jest.Jeśli chcesz
d1
mieć pierwszeństwo w konfliktach, zrób:W przeciwnym razie odwróć
d2
id1
.źródło
Moim rozwiązaniem jest zdefiniowanie funkcji scalania . To nie jest skomplikowane i kosztuje tylko jedną linię. Oto kod w Pythonie 3.
from functools import reduce from operator import or_ def merge(*dicts): return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }
Testy
>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} >>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} >>> merge(d, d_letters) {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} >>> merge(d_letters, d) {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} >>> merge(d) {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} >>> merge(d_letters) {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} >>> merge() {}
Działa dla dowolnej liczby argumentów słownikowych. Gdyby w tym słowniku były jakieś zduplikowane klucze, wygrywa klucz ze słownika znajdującego się najbardziej po prawej stronie na liście argumentów.
źródło
.update
wywołaniem (merged={}
po którym następujefor d in dict: merged.update(d)
) byłaby krótsza, bardziej czytelna i wydajniejsza.reduce
ilambda
s, co powiesz na toreturn reduce(lambda x, y: x.update(y) or x, dicts, {})
?Trey Hunner ma fajny wpis na blogu przedstawiający kilka opcji łączenia wielu słowników, w tym (dla python3.3 +) ChainMap i rozpakowywanie słownika .
źródło
Rozpoczynając od
Python 3.9
, operator|
tworzy nowy słownik ze scalonymi kluczami i wartościami z dwóch słowników:# d1 = { 'a': 1, 'b': 2 } # d2 = { 'b': 1, 'c': 3 } d3 = d2 | d1 # d3: {'b': 2, 'c': 3, 'a': 1}
To:
Zwróć także uwagę na
|=
operator, który modyfikuje d2 przez scalenie d1, z priorytetem na wartościach d1:# d1 = { 'a': 1, 'b': 2 } # d2 = { 'b': 1, 'c': 3 } d2 |= d1 # d2: {'b': 2, 'c': 3, 'a': 1}
źródło
Uważam, że, jak wspomniano powyżej, używanie
d2.update(d1)
jest najlepszym podejściem i że możesz również skopiowaćd2
najpierw, jeśli nadal tego potrzebujesz.Chociaż chcę
dict(d1, **d2)
zauważyć, że jest to w rzeczywistości zły sposób łączenia słowników w ogóle, ponieważ argumenty słów kluczowych muszą być ciągami, więc nie powiedzie się, jeśli maszdict
taki jak:{ 1: 'foo', 2: 'bar' }
źródło