Jak połączyć dwa słowniki w jedno wyrażenie?
Mam dwa słowniki Pythona i chcę napisać jedno wyrażenie, które zwróci te dwa słowniki, połączone. Metoda update()
byłaby tym, czego potrzebuję, jeśli zwróci wynik zamiast zmodyfikować dict w miejscu.
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}
Jak mogę dostać ten ostatni scalony dict w z
, a nie x
?
(żeby było wyjątkowo jasne, ostatni-wygrywa obsługę konfliktu dict.update()
jest tym, czego również Szukam.)
30 answers
Jak połączyć dwa słowniki Pythona w jedno wyrażenie?
Dla słowników x
i y
, z
staje się połączonym słownikiem z wartościami z y
, zastępując te z x
.
-
W Pythonie 3.5 lub nowszym:
z = {**x, **y} w = {'foo': 'bar', 'baz': 'qux', **y} # merge a dict with literal values
-
W Pythonie 2 (lub 3.4 lub niższym) napisz funkcję:
def merge_two_dicts(x, y): z = x.copy() # start with x's keys and values z.update(y) # modifies z with y's keys and values & returns None return z
I
z = merge_two_dicts(x, y)
Wyjaśnienie
Powiedzmy, że masz dwa dicty i chcesz je połączyć w nowy dict bez zmiany oryginalnych dict:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
Pożądanym rezultatem jest uzyskanie nowego słownika (z
) z wartościami scalonymi, a wartości drugiego dict zastępują wartości z pierwszego.
>>> z
{'a': 1, 'b': 3, 'c': 4}
W Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5]}
z = {**x, **y}
I rzeczywiście jest to jedno wyrażenie. Jest teraz pokazywany jako zaimplementowany w harmonogramie wydania dla 3.5, PEP 478, a teraz zrobił jego droga do Co nowego w Pythonie 3.5 dokumentu.
Jednakże, ponieważ wiele organizacji nadal korzysta z Pythona 2, możesz chcieć to zrobić w sposób zgodny wstecz. W Pythonie 3.0 i Pythonie 3.0-3.4 można to zrobić w dwuetapowy sposób:
z = x.copy()
z.update(y) # which returns None since it mutates z
W obu podejściach, y
będzie drugie, a jego wartości zastąpią x
wartości, więc 'b'
wskaże 3
w naszym ostatecznym wyniku.
Jeszcze nie na Pythonie 3.5, ale chcesz pojedyncze wyrażenie
Jeśli nie używasz jeszcze Pythona 3.5 lub musisz napisać wstecznie zgodny kod i chcesz to zrobić w pojedynczym wyrażeniu , najbardziej wydajnym przy prawidłowym podejściu jest umieszczenie go w funkcji:
def merge_two_dicts(x, y):
"""Given two dicts, merge them into a new dict as a shallow copy."""
z = x.copy()
z.update(y)
return z
I wtedy masz jedno wyrażenie:
z = merge_two_dicts(x, y)
Można również utworzyć funkcję scalającą niezdefiniowaną liczbę dictów, od zera do bardzo dużej liczby:
def merge_dicts(*dict_args):
"""
Given any number of dicts, shallow copy and merge into a new dict,
precedence goes to key value pairs in latter dicts.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
Ta funkcja będzie działać w Pythonie 2 i 3 dla wszystkich dictów. np. podane dikty a
do g
:
z = merge_dicts(a, b, c, d, e, f, g)
I pary wartości klucza w {[38] } będą miały pierwszeństwo przed dictami a
do f
, i tak dalej.
Krytyka innych odpowiedzi
Nie używaj tego, co widzisz w wcześniej zaakceptowanej odpowiedzi:
z = dict(x.items() + y.items())
W Pythonie 2, tworzysz dwie listy w pamięci dla każdego dict, tworzysz trzecią listę w pamięci o długości równej długości dwóch pierwszych razem złożonych, a następnie odrzucasz wszystkie trzy listy, aby utworzyć dict. w Pythonie 3 to się nie powiedzie ponieważ dodajesz dwa dict_items
obiekty razem, a nie dwie listy -
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'
I musiałbyś jawnie utworzyć je jako listy, np. z = dict(list(x.items()) + list(y.items()))
. Jest to strata zasobów i mocy obliczeniowej.
Podobnie, użycie Unii items()
w Pythonie 3 (viewitems()
w Pythonie 2.7) również nie powiedzie się, gdy wartości są obiektami niehaszowalnymi (np. listami). Nawet jeśli twoje wartości są hashowalne, ponieważ zestawy nie są semantycznie uporządkowane, zachowanie jest nieokreślone w odniesieniu do pierwszeństwa. Więc nie rób tego:
>>> c = dict(a.items() | b.items())
Ten przykład pokazuje, co się dzieje, gdy wartości są niehaszowalne:
>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Oto przykład, w którym y powinno mieć pierwszeństwo, ale zamiast tego wartość z x jest zachowana ze względu na arbitralną kolejność zbiorów:
>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}
Kolejny hack, którego nie powinieneś używać:
z = dict(x, **y)
Używa konstruktora dict
i jest bardzo szybki i wydajny w pamięci (nawet nieco bardziej-niż nasz dwuetapowy proces), ale jeśli nie wiesz dokładnie, co się tutaj dzieje (to znaczy, drugi dict jest przekazywany jako argumenty kluczowe do konstruktora dict), jest to trudne do odczytania, nie jest to zamierzone użycie, a więc nie jest to Pythonic.
Oto przykład użycia naprawionego w django .
Dict są przeznaczone do przyjmowania kluczy hashable (np. frozensets lub krotki), ale ta metoda zawodzi w Pythonie 3, gdy klucze nie są struny.
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
[59]}Z listy dyskusyjnej , Guido van Rossum, twórca języka, napisał:
I ' m fine with deklarowanie dict({}, **{1:3}) nielegalne, ponieważ przecież jest to nadużycie mechanizm**.
I
Widocznie dict(x, **y) chodzi jak "cool hack" dla " call X. update (y) I return x". Osobiście uważam to za bardziej podłe niż Super.
To jest moje zrozumienie (jak również jako zrozumienie twórcy języka), że zamierzone użycie dict(**y)
ma na celu stworzenie dyktowania dla celów czytelności, na przykład:
dict(a=1, b=10, c=11)
Zamiast
{'a': 1, 'b': 10, 'c': 11}
Odpowiedź na komentarze
Wbrew temu, co mówi Guido,
dict(x, **y)
jest zgodne ze specyfikacją dict, która btw. działa zarówno dla Pythona 2 jak i 3. Fakt, że działa to tylko dla kluczy łańcuchowych, jest bezpośrednią konsekwencją działania parametrów słów kluczowych, a nie krótkiego dict. Użycie w tym miejscu operatora ** nie jest też nadużyciem mechanizmu, w rzeczywistości ** został zaprojektowany właśnie po to, aby przekazywać dicty jako słowa kluczowe.
Ponownie, nie działa dla 3, gdy klucze nie są ciągami. Implicit calling contract polega na tym, że przestrzenie nazw przyjmują zwykłe dicty, podczas gdy użytkownicy muszą przekazywać tylko argumenty słów kluczowych, które są ciągami znaków. Wszystkie inne wezwania go egzekwowały. dict
złamał tę spójność w Pythonie 2:
>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}
Ta niespójność była zła, biorąc pod uwagę inne implementacje Python (Pypy, Jython, IronPython). W ten sposób został on poprawiony w Pythonie 3, ponieważ to użycie może być przełomową zmianą.
Oświadczam, że złośliwą niekompetencją jest celowe pisanie kodu, który działa tylko w jednej wersji języka lub który działa tylko z pewnymi arbitralnymi ograniczeniami.
Kolejny komentarz:
dict(x.items() + y.items())
jest nadal najbardziej czytelnym rozwiązaniem dla Pythona 2. Liczy się czytelność.
Moja odpowiedź: merge_two_dicts(x, y)
faktycznie wydaje się dużo dla mnie jaśniejsze, jeśli naprawdę zależy nam na czytelności. I nie jest kompatybilny z forward, ponieważ Python 2 jest coraz bardziej przestarzały.
Mniej wydajny, ale poprawny Ad-hocs
[59]}te podejścia są mniej wydajne, ale zapewnią poprawne zachowanie. Będą one znacznie mniej performatywne niżcopy
i update
lub nowe rozpakowywanie, ponieważ iterują przez każdą parę klucz-wartość na wyższym poziomie abstrakcji, aleszanują kolejność pierwszeństwo (Ostatnie dicki mają pierwszeństwo)
Można również ręcznie łańcuchować dict wewnątrz rozumienia dict:
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7
W Pythonie 2.6 (i być może już w 2.4, kiedy wprowadzono wyrażenia generatora):
dict((k, v) for d in dicts for k, v in d.items())
itertools.chain
będzie łączyć Iteratory nad parami klucz-wartość w odpowiedniej kolejności:
import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))
Analiza Wydajności
Przeprowadzę tylko analizę wydajności zwyczajów, o których wiadomo, że zachowują się poprawnie.
import timeit
Na Ubuntu 14.04 wykonujemy następujące czynności]}
W Pythonie 2.7 (Python systemowy):
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934
W Pythonie 3.5 (deadsnakes PPA):
>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287
Zasoby na słownikach
- moje wyjaśnienie implementacji słownika Pythona , zaktualizowanej do wersji 3.6.
- odpowiedź na pytanie Jak dodać nowe klucze do słownika
- mapowanie dwóch list do słownika
- oficjalny Python docs na słownikach
- W 2017 roku na targach Pycon 2017 odbyła się konferencja "Słownik jeszcze mocniejszy", której autorem jest Brandon Rhodes.]}
- [231]}Współczesne Słowniki Pythona, zbieg wspaniałych pomysłów
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-03 17:02:21
W Twoim przypadku, to co możesz zrobić to:
z = dict(x.items() + y.items())
To, jak chcesz, umieści końcowy dict w z
i sprawi, że wartość klucza b
będzie odpowiednio przesłonięta przez drugą (y
) wartość dict:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}
Jeśli używasz Pythona 3, jest to tylko trochę bardziej skomplikowane. Aby utworzyć z
:
>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 17:18:02
Alternatywa:
z = x.copy()
z.update(y)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 13:00:46
Inna, bardziej zwięzła opcja:
z = dict(x, **y)
Uwaga: ta odpowiedź stała się popularną odpowiedzią, ale ważne jest, aby zwrócić uwagę, że jeśli y
ma jakieś klucze nietekstowe, fakt, że to działa, jest nadużyciem szczegółów implementacji CPython i nie działa w Pythonie 3, ani w PyPy, IronPython lub Jython. Ponadto, Guido nie jest fanem . Więc nie mogę polecić tej techniki dla kompatybilnego lub cross-implementacji przenośnego kodu, co naprawdę oznacza, że powinno być unikał całkowicie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 06:43:24
Prawdopodobnie nie będzie to popularna odpowiedź, ale prawie na pewno nie chcesz tego robić. Jeśli chcesz mieć kopię scaloną, użyj copy (lub deepcopy , w zależności od tego, co chcesz), a następnie zaktualizuj. Dwie linie kodu są znacznie bardziej czytelne - bardziej Pythoniczne-niż tworzenie pojedynczej linii .items() + .pozycji(). Explicit jest lepszy niż implicit.
Dodatkowo, gdy używasz .items () (pre Python 3.0), tworzysz nową listę zawierającą elementy z dict. Jeśli Twoje słowniki są duże, to jest to sporo narzutu (dwie duże listy, które zostaną wyrzucone zaraz po utworzeniu scalonego dict). update() może działać wydajniej, ponieważ może działać przez drugi dict pozycja po pozycji.
W kategoriach czasu :
>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027
IMO małe spowolnienie między dwoma pierwszymi jest tego warte ze względu na czytelność. Dodatkowo argumenty słów kluczowych do tworzenia słownika zostały dodane tylko w Pythonie 2.3, podczas gdy copy () i update() będzie działać w starszych wersjach.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-05 23:56:02
W odpowiedzi uzupełniającej zapytałeś o względną wydajność tych dwóch alternatyw:
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)
Na moim komputerze, przynajmniej (dość zwykły x86_64 z Pythonem 2.5.2), alternatywa z2
jest nie tylko krótsza i prostsza, ale także znacznie szybsza. Możesz to sprawdzić samodzielnie za pomocą modułu timeit
dostarczanego z Pythonem.
Przykład 1: identyczne słowniki odwzorowujące 20 kolejnych liczb całkowitych do siebie:
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)'
100000 loops, best of 3: 1.53 usec per loop
z2
wygrane przez współczynnik 3,5 mniej więcej. Różne słowniki wydają się dawać zupełnie inne wyniki, ale z2
zawsze wydają się wychodzić na wierzch. (Jeśli uzyskasz niespójne wyniki dla tego samego testu, spróbuj przejść -r
z liczbą większą niż domyślna 3.)
Przykład 2: nie nakładające się słowniki odwzorowują 252 krótkie ciągi na liczby całkowite i odwrotnie:
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'
10000 loops, best of 3: 26.9 usec per loop
z2
wygrywa o współczynnik 10. To całkiem duża wygrana w mojej książce!
Po porównaniu tych dwóch, zastanawiałem się, czy Słaba wydajność może być przypisana do kosztów budowy dwóch list przedmiotów, co z kolei skłoniło mnie do zastanowienia się, czy ta odmiana może działać lepiej:]}
from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))
Kilka szybkich testów, np.
% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop
Doprowadzaj mnie do wniosku, że z3
jest nieco szybszy niż z1
, ale nie prawie tak szybki jak z2
. Zdecydowanie nie warto wszystkich dodatkowych wpisów.
W tej dyskusji wciąż brakuje czegoś ważnego, czyli porównania wydajności tych alternatyw z "oczywisty" sposób łączenia dwóch list: za pomocą metody update
. Aby spróbować utrzymać rzeczy na równi z wyrażeniami, z których żadne nie modyfikuje x lub y, zrobię kopię x zamiast modyfikować go na miejscu, w następujący sposób: {]}
z0 = dict(x)
z0.update(y)
Typowy wynik:
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop
Innymi słowy, z0
i z2
wydają się mieć zasadniczo identyczne wyniki. Myślisz, że to może być zbieg okoliczności? Ja nie....
W rzeczywistości posunąłbym się nawet do twierdzenia, że to niemożliwe aby czysty kod Pythona był lepszy niż ten. A jeśli możesz zrobić znacznie lepiej w module rozszerzeń C, wyobrażam sobie, że ludzie Pythona mogą być zainteresowani włączeniem Twojego kodu (lub wariacji na temat Twojego podejścia) do rdzenia Pythona. Python używa dict
w wielu miejscach; optymalizacja jego operacji to wielka sprawa.
Możesz też napisać to jako
z0 = x.copy()
z0.update(y)
Tak jak Tony, ale (nic dziwnego) różnica w notacji okazuje się nie mieć żadnego mierzalnego efektu na wydajność. Użyj tego, co Ci odpowiada. Oczywiście ma absolutną rację zaznaczając, że wersja dwuznakowa jest znacznie łatwiejsza do zrozumienia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-10 02:32:55
Chciałem coś podobnego, ale z możliwością określenia, jak wartości na zduplikowanych kluczach zostały połączone, więc hacked to out (ale nie mocno testować). Oczywiście nie jest to pojedyncze wyrażenie, ale jedno wywołanie funkcji.
def merge(d1, d2, merge_fn=lambda x,y:y):
"""
Merges two dictionaries, non-destructively, combining
values on duplicate keys as defined by the optional merge
function. The default behavior replaces the values in d1
with corresponding values in d2. (There is no other generally
applicable merge strategy, but often you'll have homogeneous
types in your dicts, so specifying a merge technique can be
valuable.)
Examples:
>>> d1
{'a': 1, 'c': 3, 'b': 2}
>>> merge(d1, d1)
{'a': 1, 'c': 3, 'b': 2}
>>> merge(d1, d1, lambda x,y: x+y)
{'a': 2, 'c': 6, 'b': 4}
"""
result = dict(d1)
for k,v in d2.iteritems():
if k in result:
result[k] = merge_fn(result[k], v)
else:
result[k] = v
return result
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-13 19:56:21
W Pythonie 3 możesz użyć Kolekcje.ChainMap który grupuje wiele dictów lub innych mapowań razem, aby utworzyć jeden, aktualizowalny Widok:
>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
print(k, '-->', v)
a --> 1
b --> 10
c --> 11
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-27 08:12:41
Recursively / deep update a dict
def deepupdate(original, update):
"""
Recursively update a dict.
Subdict's won't be overwritten but also updated.
"""
for key, value in original.iteritems():
if key not in update:
update[key] = value
elif isinstance(value, dict):
deepupdate(value, update[key])
return update
Demonstracja:
pluto_original = {
'name': 'Pluto',
'details': {
'tail': True,
'color': 'orange'
}
}
pluto_update = {
'name': 'Pluutoo',
'details': {
'color': 'blue'
}
}
print deepupdate(pluto_original, pluto_update)
Wyjścia:
{
'name': 'Pluutoo',
'details': {
'color': 'blue',
'tail': True
}
}
Dzięki rednaw za edycje.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-18 11:19:15
Najlepsza wersja, jaką mogłem sobie wyobrazić, gdy nie używałem copy to:
from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))
Jest szybszy niż dict(x.items() + y.items())
, ale nie tak szybki jak n = copy(a); n.update(b)
, przynajmniej na Cpythonie. Ta wersja działa również w Pythonie 3, Jeśli zmienisz iteritems()
na items()
, co jest automatycznie wykonywane przez narzędzie 2to3.
Osobiście najbardziej podoba mi się ta wersja, ponieważ opisuje dość dobre to, co chcę w jednej składni funkcjonalnej. Jedynym drobnym problemem jest to, że nie jest całkowicie oczywiste, że wartości z y ma pierwszeństwo ponad wartościami z x, ale nie wydaje mi się, że trudno to rozgryźć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-14 18:55:15
Python 3.5 (PEP 448) pozwala na ładniejszą opcję składni:
x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y}
final
# {'a': 2, 'b': 1, 'c': 2}
Lub nawet
final = {'a': 1, 'b': 1, **x, **y}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-26 21:27:52
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z
Dla elementów z kluczami w obu słownikach ('b'), możesz kontrolować, który z nich kończy się na wyjściu, umieszczając go na końcu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 07:49:27
Podczas gdy na pytanie już kilka razy udzielono odpowiedzi, to proste rozwiązanie problemu nie zostało jeszcze wymienione.
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)
Jest tak szybki jak Z0 i zło Z2 wymienione powyżej, ale łatwy do zrozumienia i zmiany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-14 16:12:33
def dict_merge(a, b):
c = a.copy()
c.update(b)
return c
new = dict_merge(old, extras)
Wśród takich niejasnych i wątpliwych odpowiedzi, Ten świecący przykład jest jedynym i jedynym dobrym sposobem łączenia dictów w Pythonie, zatwierdzonym przez samego dictator for life[4]}Guido van Rossum[5]}! Ktoś inny zasugerował połowę tego, ale nie umieścił go w funkcji.
print dict_merge(
{'color':'red', 'model':'Mini'},
{'model':'Ferrari', 'owner':'Carl'})
Daje:
{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-06 09:30:07
Jeśli uważasz, że lambda są złe, nie czytaj dalej. Zgodnie z życzeniem, możesz napisać szybkie i efektywne w pamięci rozwiązanie za pomocą jednego wyrażenia:
x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}
Jak sugerowano powyżej, używanie dwóch linii lub pisanie funkcji jest prawdopodobnie lepszym rozwiązaniem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-23 18:20:48
z={i:d[i] for d in [x,y] for i in d}
>>> print z
{'a': 1, 'c': 11, 'b': 10}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 10:45:25
W python3, metoda items
nie zwraca już listy, ale raczej widok, który działa jak zbiór. W tym przypadku musisz wziąć zestaw Unia ponieważ konkatenacja z +
nie będzie działać:
dict(x.items() | y.items())
Dla zachowania przypominającego python3 w wersji 2.7, metoda viewitems
powinna działać zamiast items
:
dict(x.viewitems() | y.viewitems())
I tak wolę tę notację, ponieważ bardziej naturalne wydaje się myślenie o niej jako o operacji zespolonej, a nie konkatenacji (jak w tytule pokazy).
Edit:
Jeszcze kilka punktów dla Pythona 3. Po pierwsze, zauważ, że sztuczka dict(x, **y)
nie będzie działać w Pythonie 3, chyba że klucze y
są ciągami znaków.
Również odpowiedź Raymonda Hettingera Chainmap jest dość elegancka, ponieważ może przyjmować dowolną liczbę dictów jako argumentów, ale z dokumentów wygląda tak, jakby kolejno przeglądała listę wszystkich dictów dla każdego wyszukiwania:
Szukaj Szukaj mapuje kolejno, aż do znalezienia klucza.
Może to spowolnić, jeśli masz dużo wyszukiwania w aplikacji:
In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop
Więc o rząd wielkości wolniej dla wyszukiwania. Jestem fanem Chainmap, ale wygląda mniej praktycznie tam, gdzie może być wiele wyszukiwań.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53
Nadużycie prowadzące do rozwiązania jednego wyrażenia dla odpowiedź Mateusza :
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}
Powiedziałeś, że chcesz jedno wyrażenie, więc wykorzystałem lambda
, aby powiązać nazwę, i krotki, aby zastąpić limit jednego wyrażenia lambda. Nie krępuj się.
Możesz to oczywiście zrobić, jeśli nie zależy ci na kopiowaniu:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53
Proste rozwiązanie przy użyciu itertools, które zachowuje porządek (Ostatnie dicty mają pierwszeństwo)
import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))
I jego użycie:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}
>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-06 11:30:16
Dwa słowniki
def union2(dict1, dict2):
return dict(list(dict1.items()) + list(dict2.items()))
N słowniki
def union(*dicts):
return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))
sum
ma złe wyniki. Zobacz https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-02 18:16:17
W Pythonie 3:
import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}
r = dict(collections.ChainMap(a, b, c))
print(r)
Out:
{1: 1, 2: 2, 3: 4}
Docs: https://docs.python.org/3/library/collections.html#collections.ChainMap :
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-24 07:24:50
Mimo że odpowiedzi były dobre dla tego słownikashallow , żadna z metod zdefiniowanych tutaj nie łączy głębokiego słownika.
Przykłady:
a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())
Można by się spodziewać wyniku czegoś takiego:
{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }
Zamiast tego otrzymujemy:
{'two': True, 'one': {'extra': False}}
Wpis 'one' powinien mieć 'depth_2' i 'extra' jako elementy w słowniku, jeśli rzeczywiście było to połączenie.
Używanie łańcucha również nie działa:
from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))
Wyniki in:
{'two': True, 'one': {'extra': False}}
Głębokie scalenie, które dało rcwesick, również tworzy ten sam wynik.
Tak, będzie działać scalanie przykładowych słowników, ale żaden z nich nie jest ogólnym mechanizmem scalania. Zaktualizuję to później, gdy napiszę metodę, która wykonuje prawdziwe scalanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-03 23:36:50
Dla Pythona 2:
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()+y.items())
print(z)
Dla Pythona 3:
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()|y.items())
print(z)
Daje wyjście: {'a': 1, 'c': 11, 'b': 10}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-01 06:29:01
Czerpiąc z pomysłów tu i gdzie indziej pojąłem funkcję:
def merge(*dicts, **kv):
return { k:v for d in list(dicts) + [kv] for k,v in d.items() }
Użycie (testowane w Pythonie 3):
assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
{1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})
assert (merge(foo='bar')=={'foo': 'bar'})
assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
{1: 99, 'foo': 'bar', 'baz':'quux'})
assert (merge({1:11},{1:99})=={1: 99})
Zamiast tego możesz użyć lambdy.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-19 05:49:19
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-13 10:01:31
Problem, który mam z rozwiązaniami wymienionymi do tej pory, polega na tym, że w połączonym słowniku wartość klucza " b " wynosi 10, ale moim zdaniem powinno być to 12. W tym świetle przedstawiam następujące:
import timeit
n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""
def timeMerge(f,su,niter):
print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)
timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)
#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x
Wyniki:
0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)
0.150380 sec for: dict(x.items() + y.items())
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 18:11:54
Można to zrobić za pomocą jednego słownika:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
for key in set(x) + set(y)
}
Moim zdaniem najlepsza odpowiedź dla części 'single expression', ponieważ nie są potrzebne żadne dodatkowe funkcje i jest krótka.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-17 14:47:23
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))
To powinno rozwiązać twój problem.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-30 13:04:00
(Tylko dla Python2. 7*; istnieją prostsze rozwiązania dla Python3*.)
Jeśli nie jesteś przeciwny importowaniu standardowego modułu bibliotecznego, możesz to zrobić
from functools import reduce
def merge_dicts(*dicts):
return reduce(lambda a, d: a.update(d) or a, dicts, {})
(bit or a
w lambda
jest konieczny, ponieważ dict.update
zawsze zwraca None
Po sukcesie.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-28 13:13:27
W Pythonie 3.5 możesz użyć unpack **
w celu utworzenia nowego słownika.
Metoda ta nie została wykazana w poprzednich odpowiedziach. Ponadto, lepiej jest użyć {}
zamiast dict()
. Ponieważ {}
jest literałem Pythona, a dict()
zawiera wywołanie funkcji.
dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-28 00:33:55