Bir ifadədə iki lüğəti necə birləşdirmək olar?

Mənim iki Python lüğət var və mən bu iki lüğətləri birləşdirən bir ifadə yazmaq istəyirəm. update() metodu, nəticəni verərsə, mənə lazım olan şey olacaq və dictin yerini dəyişmir.

 >>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = x.update(y) >>> print(z) None >>> x {'a': 1, 'b': 10, 'c': 11} 

Bu yekun birləşməni z deyil, x də necə əldə edə bilərəm?

( dict.update() bir dəfə dict.update() münaqişələri ilə münaqişələrin idarə edilməsi dict.update() .

3587
02 сент. Carl Meyer tərəfindən təyin olunan 02 sentyabr. 2008-09-02 10:44 '08 at 10:44 2008-09-02 10:44
@ 52 cavab
  • 1
  • 2

Bir ifadədə iki Python lüğətini necə birləşdirə bilərəm?

xy z , x dən dəyərlərin əvəzlənməsindən ibarət dəyərlərlə birləşmiş bir lüğətə çevrilir.

  • Python 3.5 və ya daha yüksək:

     z = {**x, **y} 
  • Python 2 (və ya 3.4 və ya aşağıda) bir funksiyanı yaz:

     def merge_two_dicts(x, y): z = x.copy() # start with x keys and values z.update(y) # modifies z with y keys and values  returns None return z 

    və indi:

     z = merge_two_dicts(x, y) 

izahat

Diyelim ki, iki diktansınız var və bunları orijinal olanları dəyişdirmədən yenisini birləşdirmək istəyirsiz:

 x = {'a': 1, 'b': 2} y = {'b': 3, 'c': 4} 

İstənilən nəticə birləşdirilmiş dəyərlərlə yeni bir lüğət ( z ) əldə etməkdir və ikinci dict dəyərləri birinci olan dəyərlər üzərində yazılır.

 >>> z {'a': 1, 'b': 3, 'c': 4} 

Bunun üçün yeni bir sintaksis, PEP 448-də təklif edilən və Python 3.5 ,

 z = {**x, **y} 

Və bu, həqiqətən, tək ifadədir.

Xatırladaq ki, məktub notation ilə birləşə bilərik:

 z = {**x, 'foo': 1, 'bar': 2, **y} 

və indi:

 >>> z {'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4} 

İndi 3.5-ci pillədə, PEP 478 - necə tətbiq olunduğunu göstərir və indi Python 3.5-də yeni olan sənəddə görünür.

Lakin, bir çox təşkilat Python 2-dən istifadə etdiyinə görə, onu geriyə uyğunlaşdıra bilərsiniz. Python 2 və Python 3.0-3.4-də mövcud olan klassik Pythonic metodu iki mərhələli bir proses olaraq bunu etməkdir:

 z = x.copy() z.update(y) # which returns None since it mutates z 

Hər iki yanaşmada da y ikinci olacaq və dəyərləri x nin dəyərlərini əvəz edəcək, 'b' son nəticədə isə 'b' 3 'b' göstərəcəkdir.

Hələ Python 3.5, lakin bir ifadə istəyirəm

Əgər hələ Python 3.5 istifadə etmirsinizsə və ya geri uyğun bir kod yazmanız lazımdır və bir ifadədə olmasını istəyirsinizsə, ən effektiv və düzgün yanaşma bir funksiyaya qoymaqdır:

 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 

və sonra bir ifadəiniz var:

 z = merge_two_dicts(x, y) 

Belirtilmemiş bir sıra diktatorların sıfırdan çox sayda birləşməsi üçün funksiyanı da yarada bilərsiniz:

 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 

Bu funksiya bütün dictations üçün Python 2 və 3-də işləyəcək. məsələn, məlumatlar a dan diktə edilir:

 z = merge_dicts(a, b, c, d, e, f, g) 

g - g əsas dəyər cütləri f dən parametrlərə üstünlük verir və s.

Digər cavabların tənqidi

Daha əvvəl qəbul edilən cavabda gördüyünüzü istifadə etməyin:

 z = dict(x.items() + y.items()) 

Python 2-də, hər dict üçün yaddaşda iki siyahı yaradın, ilk iki birləşmənin uzunluğuna bərabər olan uzunluğu olan yaddaşda üçüncü bir siyahısını yaradın və sonra dict yaratmaq üçün bütün üç siyahıdan silin. Python 3-də, iki dict_items birlikdə deyil, iki siyahı əlavə etdiyiniz üçün bu uğur qazanmaz -

 >>> 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' 

və bunları, məsələn, z = dict(list(x.items()) + list(y.items())) siyahıları kimi açıq şəkildə yaratmalısınız. Bu resursların və hesablama gücünün itməsi.

Eyni şəkildə, Python 3-də (Python 2.7-də viewitems() items() Python-da items() birləşdirmək də dəyərlər dəyişdirə bilməyən obyektlərdir (məsələn, siyahı). Dəyərləriniz həssas olsa belə, sütunlar semantically unordered çünki davranış prioritet bağlı müəyyən deyil. Beləliklə bunu etməyin:

 >>> c = dict(a.items() | b.items()) 

Bu nümunə dəyərləri fərqləndirə bilmədikdə nə baş verdiyini göstərir:

 >>> x = {'a': []} >>> y = {'b': []} >>> dict(x.items() | y.items()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' 

Burada y üstünlük verə bilməsi lazım olan bir nümunədir, amma x-nin dəyəri kəmiyyətlərin sıradan qaydalarından asılı olaraq saxlanılır:

 >>> x = {'a': 2} >>> y = {'a': 1} >>> dict(x.items() | y.items()) {'a': 2} 

Digər bir hack istifadə etməyin:

 z = dict(x, **y) 

Bu dict konstruktorundan istifadə edir və yaddaşdan istifadə etmək üçün çox sürətli və səmərəli olur (iki addımlı prosesimizdən bir qədər daha), amma burada nə baş verdiyini dəqiq bilmirsinizsə (yəni, ikinci dict dict konstruktiv açar sözlər üçün dəlil kimi qəbul olunur) oxumaq çətindir, istifadəsi nəzərdə tutulmur, buna görə Python deyil.

Djangoda bir düzəliş istifadə etmək nümunəsi.

Diklər hash düymələri (məsələn, frozensets və ya tuples) almaq üçün nəzərdə tutulmuşdur, lakin düymələr düymə olmayan zaman bu metod Python 3-də işləmir.

 >>> c = dict(a, **b) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: keyword arguments must be strings 

Məktub siyahısından, dilin yaradıcısı Guido van Rossum yazırdı:

Mən bir dict ({}, ** {1: 3}) bəyannaməsi ilə razıyam, çünki nəticədə ** mexanizmi sui-istifadə edir.

və həmçinin

Göründüyü kimi, dict (x, ** y) "x.update (y) zəng və x" xarakterinə "sərin hack" kimi istifadə olunur. Şəxsən mən onu sərindən daha hörmətli hesab edirəm.

Dict'in dict(**y) nəzərdə tutulan istifadəsinin okunabilirlik məqsədi dicts yaratmaq məqsədi daşıdığının anlaşılması mənim anlayışımdır ( dilin yaradıcısı kimi ): məsələn:

 dict(a=1, b=10, c=11) 

əvəzinə

 {'a': 1, 'b': 10, 'c': 11} 

Şərhlərə cavab verin

dict(x, **y) dediklərinə baxmayaraq, dict(x, **y) dict spesifikasiyasına uyğundur. həm də Python 2 və 3 üçün işləyir. Bu yalnız string düymələri üçün işlədilməkdədir, əsas söz parametrlərinin işləməsinin birbaşa nəticəsi, dictin qısa bir istifadə edilməməsi. Həmçinin, operatorun ** bu yerdən istifadəsi mexanizmin sui-istifadə edilməməsi deyil, əslində sözlərin sözlərin açılması üçün xüsusi hazırlanmışdır.

Yenə də düymələr bantlar olmadığı üçün bu 3 işləmir. Sözsüz zəng müqaviləsi müntəzəm diktasiyaların ad boşluğudur, istifadəçilər isə yalnız əsas arqumentləri keçirməlidirlər. Bütün digər hərbi qüvvələr onu zorladılar. dict Python 2-də bu ardıcıllığı qırdı:

 >>> 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} 

Bu uyğunsuzluq digər Python tətbiqləri nəzərə alınmaqla pis idi (Pypy, Jython, IronPython). Beləliklə, bu istifadə Python 3-də müəyyən edilmişdir, çünki bu istifadə böyük dəyişiklik ola bilər.

Mən bu təhqirsizliyin olduğunu iddia edirəm - qəsdən yazı yazmaq yalnız dilin bir versiyasında işləyir və ya yalnız müəyyən təsadüfi məhdudiyyətlər altında işləyir.

Daha çox şərh:

dict(x.items() + y.items()) Python 2 üçün ən oxunaqlı həlldir. Readability məsələləri.

merge_two_dicts(x, y) : merge_two_dicts(x, y) həqiqətən oxunabilirlikdən narahat olduqda mənə daha aydın görünür. Və bu irəliyə uyğun deyil, çünki Python 2 daha da köhnəlir.

{**x, **y} iç içə lüğətlər ilə əlaqəli görünmür. Daxili düymələrin məzmunu sadəcə yazılıdır, birləşməyib [...]. Sonda təkrarlanan birləşməyən bu cavablar mənə yandırıldı və mən heç kimin bunu söyləmədiyi üçün təəccübləndim. "Birləşmə" sözünün mənimsəməsində bu cavablar "bir diktanı digərinə yeniləşdirmək" və birləşməyi təsvir edir.

Bəli Bir sözlə, mənə ikinci lüğətin üstünə yazılan iki lüğətin səthi birləşməsini tələb edən bir sual göndərmək məcburiyyətindəyəm.

İki lüğət qəbul edildikdə, bir recursively onları bir funksiyaya birləşdirə bilər, ancaq hər hansı bir mənbədən istiqamətləri dəyişdirməmək üçün diqqətli olmalısınız və bunun qarşısını almaq üçün ən etibarlı bir şəkildə dəyərlər təyin edərkən surəti etməkdir. Klaviaturaların təmizlənməsinə və bununla da adətən dəyişməz olduğuna görə onları çıxarmaq heç bir mənası yoxdur:

 from copy import deepcopy def dict_of_dicts_merge(x, y): z = {} overlapping_keys = x.keys()  y.keys() for key in overlapping_keys: z[key] = dict_of_dicts_merge(x[key], y[key]) for key in x.keys() - overlapping_keys: z[key] = deepcopy(x[key]) for key in y.keys() - overlapping_keys: z[key] = deepcopy(y[key]) return z 

İstifadə edin:

 >>> x = {'a':{1:{}}, 'b': {2:{}}} >>> y = {'b':{10:{}}, 'c': {11:{}}} >>> dict_of_dicts_merge(x, y) {'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}} 

Digər dəyər növləri üçün gözlənilməz şərtlər bu sualın həddən çox uzaqdır, buna görə də sizə "Sözlərin birləşməsi lüğətləri" sualına cavab verəcəyəm .

Az məhsuldar, lakin düzgün Ad-hocs

Bu yanaşmalar daha az effektivdir, lakin onlar düzgün davranış təmin edəcəklər. Onlar hər bir açar dəyər cüt üzərində soyutmanın yüksək səviyyədə təkrarladığı üçün copyupdate və ya yeni açılmalardan daha az məhsuldar olacaqlar, lakin prioritet sırasına hörmətlə yanaşırlar (sonuncu diktə üstünlük təşkil edir)

Sözləri öz anlayışlarında əl ilə bağlaya bilərsiniz:

 {k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7 

və ya Python 2.6 (və, ehtimal ki, generator işarələri daxil olduqda artıq 2.4 olan):

 dict((k, v) for d in dicts for k, v in d.items()) 

itertools.chain iteratorları əsas dəyər cütlüyündə düzgün qaydada:

 import itertools z = dict(itertools.chain(x.iteritems(), y.iteritems())) 

Performans təhlili

Yalnız düzgün davrandıqları bilindiyi hallarda yalnız performansını təhlil edəcəyəm.

 import timeit 

Ubuntu 14.04-də aşağıdakılar edilir

Python 2.7-də (Python sistemi):

 >>> 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 

Python 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 

Lüğət resursları

3869
11 нояб. Cavab 11 noyabr tarixində Aaron Hall tərəfindən verilir. 2014-11-11 01:11 '14 at 1:11 pm 2014-11-11 01:11

Sizin vəziyyətinizdə nə edə bilərsiniz:

 z = dict(x.items() + y.items()) 

Bu, istədiyiniz kimi son dicti z qoyun və b sətri üçün ikinci dəyər ( y ) ilə dəyərin düzgün şəkildə yenidən təyin olunmasını:

border=0
 >>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = dict(x.items() + y.items()) >>> z {'a': 1, 'c': 11, 'b': 10} 

Python 3-dən istifadə etsəniz, bir az daha mürəkkəbdir. z yaratmaq üçün:

 >>> z = dict(list(x.items()) + list(y.items())) >>> z {'a': 1, 'c': 11, 'b': 10} 
1490
02 сент. Thomas Vander Stichele-ye cavab 02 Sep 2008-09-02 10:50 '08 saat 10:50 'da 2008-09-02 10:50

Alternativ:

 z = x.copy() z.update(y) 
574
02 сент. Matthew Şinckel tərəfindən verilmiş cavab 02 Sep 2008-09-02 16:00 '08 4:00 'da 2008-09-02 4:00' de

Digər, daha qısa variant:

 z = dict(x, **y) 

Qeyd : Bu populyar bir cavab oldu, ancaq y hər hansı bir qeyri-simli düymələri varsa, o zaman bütün işin həqiqətən də CPython tətbiqinin detallarının istismar olması və Python 3, PyPy, IronPython və ya Jython'da işləməyəcəyini qeyd etmək vacibdir. Bundan əlavə, Guido bir fan deyil . Buna görə də, bu metodu qabaqcıl uyğunluq və ya qarşılıqlı həyata keçirməklə taşınabilir kod üçün tövsiyə edə bilməyəcəyəm, buna görə əslində tamamilə xaric edilməlidir.

288
02 сент. Cavab Carl Meyer tərəfindən verilib 02 Sentyabr. 2008-09-02 18:52 '08 at 18:52 2008-09-02 18:52

Bu, yəqin ki, məşhur cavab olmayacaq, amma demək olar ki, bunu etmək istəmirsiniz. Birləşmənin bir nüsxəsinə ehtiyacınız varsa, istədiyiniz surətdə (və ya dərinliyə görə) bir surəti istifadə edin və sonra yeniləyin. Daha çox Pythonic kodu - iki satır kodu çox oxunaqlıdır - .items () + .items () istifadə edərək, bir xətt yaratmaqdan çox. Açık-aydın örtükdən daha yaxşıdır.

Bundan əlavə, istifadə etdiyiniz zaman .items () (əvvəlcədən Python 3.0), dict olan elementləri olan yeni bir siyahı yaradın. Sözlükleriniz böyükse, bir çox yer üstü (kombinə edilmiş bir dict yaratıldığı anda atılacaq iki böyük siyahı) var. yeniləmə () daha effektiv işləyə bilər, çünki ikinci hissədə işlədilə bilər.

Zaman baxımından:

 >>> 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 ilk iki dəyərli oxuma arasında kiçik bir yavaşlama. Bundan əlavə, sözün lüğəti argumentləri yalnız Python 2.3-də əlavə edilib, surəti () və yeniləmə () isə köhnə versiyalarda işləyəcəkdir.

178
08 сент. Cavab Tony Meyer tərəfindən verilir. 2008-09-08 14:16 '08 at 2:16 pm 2008-09-08 14:16

Aşağıdakı cavabda bu iki alternativin nisbi performansı haqqında soruşdunuz:

 z1 = dict(x.items() + y.items()) z2 = dict(x, **y) 

Mənim maşınımda ən azı (olduqca x86_64, Python 2.5.2 ilə işləyən) alternativ z2 yalnız daha qısa və daha asan deyil, həm də daha sürətli. Python ilə gələn timeit modulu istifadə edərək özünüzü test edə bilərsiniz.

Məsələn: 20 ardıcıl tamsayı göstərən eyni lüğətlər:

 % 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 3,5 dəfə və ya daha çox qazanır. Göründüyü kimi, müxtəlif lüğətlər tamamilə fərqli nəticələr verir, lakin z2 həmişə irəlidə görünür. (Eyni test üçün uyğun olmayan nəticələr əldə etsəniz, default-dən daha çox sayı ilə -r keçməyi cəhd edin.)

Misal 2: tamsayılar üçün 252 qısa simli və əksinə göstərən qeyri-örtülü lüğətlər:

 % 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 təxminən 10 dəfə qalib gəlir. Bu mənim kitabımda olduqca böyük bir qalibiyyətdir!

Bu ikisini müqayisə etdikdən sonra z1 pis işi, bu dəyişmənin daha yaxşı işləməyəcəyini təəccübləndirməyimə səbəb olan maddələrin iki siyahısının yaradılması ilə bağlı ola bilərmi?

 from itertools import chain z3 = dict(chain(x.iteritems(), y.iteritems())) 

Bəzi sürətli testlər, məsələn

 % 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 

mənə z3 dən bir qədər daha sürətli olduğunu ancaq z3 sürətli olmayan nəticəyə z3 . Əlbəttə ki, bütün əlavə yazmağa ehtiyac yoxdur.

Bu mübahisədə hələ də bu alternativlərin performansını iki siyahıdan birləşmənin "aydın" üsulu ilə müqayisə edən əhəmiyyətli bir şey var: update metodundan istifadə. Hansı şeyi x və ya y dəyişməyəcək şəkildə ifadələrlə bərabər səviyyədə saxlamağa çalışmaq üçün x kimi bir yerə dəyişdirmək yerinə x nüsxəsini çıxaracağam:

 z0 = dict(x) z0.update(y) 

Tipik nəticə:

 % 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 

Başqa sözlə, z0z2 demək olar ki, eyni görünür. Bu təsadüf ola bilərmi? Bilmirəm ...

Əslində, təmiz Python kodunun bundan daha yaxşı bir şey etməsi mümkün olmadığını iddia etmək üçün indiyə qədər gedəcəyəm. Və C extension modulunda daha yaxşı işləyə bilsəniz, Python insanları kodunuzu (ya da yanaşma varyasyonlarını) Python əsasına daxil etməklə maraqlana bilər. Python bir çox yerdə dict istifadə edir; əməliyyatlarını optimallaşdırmaq böyük bir işdir.

Bunu da yaza bilərsiniz

 z0 = x.copy() z0.update(y) 

Tony kimi, amma (təəccüblü deyil) qeyddə fərq fərqli bir nəticə vermir. Sizə uyğun olanı istifadə edin. Əlbəttə ki, iki ifadəsi olan bir versiyanı başa düşmək daha asan olduğunu göstərir.

123
23 окт. 23 oktyabr tarixində cavab verildi . 2008-10-23 05:38 '08 at 5:38 2008-10-23 05:38

Bənzər bir şey istədim amma təkrarlanan əsas dəyərlərin necə birləşdirildiyini müəyyən etmək qabiliyyəti ilə, hacked (lakin çox test etmədi). Aydındır ki, bu bir ifadə deyil, bir funksional çağırışdır.

 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 
91
04 сент. Cavab sentyabrın 4-də rcreswick tərəfindən verilir 2008-09-04 22:08 '08 saat 10:08 'da 2008-09-04 22:08

Python 3-də, koleksiyonlardan istifadə edə bilərsiniz. Bir neçə dictations və ya digər mappings birləşdirən bir yeniləməli görünüş yaratmaq üçün birləşdirən ChainMap:

 >>> 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 
82
28 апр. Raymond Hettinger tərəfindən verilən cavabı Apr 28 2013-04-28 06:15 '13 saat 6:15 'da 2013-04-28 06:15

Rəqəmsal / dərin yeniləmə dict

 def deepupdate(original, update): """ Recursively update a dict. Subdict 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 

Demonstration:

 pluto_original = { 'name': 'Pluto', 'details': { 'tail': True, 'color': 'orange' } } pluto_update = { 'name': 'Pluutoo', 'details': { 'color': 'blue' } } print deepupdate(pluto_original, pluto_update) 

Çıxışlar:

 { 'name': 'Pluutoo', 'details': { 'color': 'blue', 'tail': True } } 

Dəyişikliklər üçün yenidən baxın.

66
29 нояб. Cavab verilir Stan 29 noyabr. 2011-11-29 14:52 '11 at 14:52 2011-11-29 14:52

Bir surəti istifadə etmədən düşünə biləcəyim ən yaxşı versiya:

 from itertools import chain x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} dict(chain(x.iteritems(), y.iteritems())) 

Bu dict(x.items() + y.items()) sürətli, lakin n = copy(a); n.update(b) kimi sürətli deyil n = copy(a); n.update(b) n = copy(a); n.update(b) , ən az CPython. Bu versiya həmçinin 2to3 alətindən istifadə edərək avtomatik olaraq işlənən items() iteritems() dəyişdirirsinizsə Python 3-də də işləyir.

Şəxsən mən bu versiyanı ən yaxşıları sevirəm, çünki bir funksional sintaktikada istədiyim çox yaxşı bir şeyi təsvir edir. Yalnız kiçik problem odur ki, y dəyərlər x-dən dəyərlərə üstünlük verir, amma başa düşmək çətin deyil.

58
14 окт. 14 aya qədər cavab verildi . 2010-10-14 21:55 '10 at 21:55 2010-10-14 21:55
 x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items() + y.items()) print z 

Hər iki lüğətdə ('b') açarları olan maddələr üçün onların sonrakı yerlərini yerləşdirərək onların hansı məhsula düşdüyünü nəzarət edə bilərsiniz.

46
02 сент. Greg Hewgill tərəfindən verilmiş cavab 02 Sentyabr 2008-09-02 10:49 '08 saat 10:49 'da 2008-09-02 10:49

Python 3.5 (PEP 448) daha rahat bir sözdizimi seçməyə imkan verir:

 x = {'a': 1, 'b': 1} y = {'a': 2, 'c': 2} final = {**x, **y} final # {'a': 2, 'b': 1, 'c': 2} 

Və ya hətta

 final = {'a': 1, 'b': 1, **x, **y} 
46
27 февр. cavab 27 fevralda Bilal Syed Hussain tərəfindən verilir 2015-02-27 00:27 '15 at 0:27 2015-02-27 00:27

Sual bir neçə dəfə cavablandırılmış olsa da, problemin bu sadə həlli hələ göstərilməyib.

 x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z4 = {} z4.update(x) z4.update(y) 

Bu, yuxarıda göstərilən z0 və pis z2 kimi ancaq anlamaq və dəyişdirmək üçün asandır.

39
14 окт. cavab fobiyə 14 okt verilir . 2011-10-14 19:12 '11 at 19:12 2011-10-14 19:12
 def dict_merge(a, b): c = a.copy() c.update(b) return c new = dict_merge(old, extras) 

Belə kölgəli və şübhəli cavablar arasında, bu parlaq nümunə Guido van Rossumun özü üçün diktator tərəfindən təsdiqlənmiş Python'a diktofonların birləşdirilməsinin yeganə və yeganə yoludur! Biri bunun yarısını təklif etdi, lakin funksiyanı daxil etməyib.

 print dict_merge( {'color':'red', 'model':'Mini'}, {'model':'Ferrari', 'owner':'Carl'}) 

verir:

 {'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'} 
36
ответ дан Sam Watkins 06 авг. '12 в 12:24 2012-08-06 12:24

Если вы думаете, что лямбды злы, тогда не читайте дальше. В соответствии с запросом вы можете написать быстрое и экономичное решение с одним выражением:

 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} 

Как было сказано выше, использование двух строк или запись функции, вероятно, является лучшим способом.

29
ответ дан EMS 23 нояб. '11 в 21:08 2011-11-23 21:08

Быть питоническим. Используйте понимание :

 z={i:d[i] for d in [x,y] for i in d} >>> print z {'a': 1, 'c': 11, 'b': 10} 
24
ответ дан Robino 20 янв. '16 в 14:46 2016-01-20 14:46

В python3 метод items больше не возвращает список , а скорее представление, которое действует как набор. В этом случае вам понадобится принять объединение соединений, так как конкатенация с помощью + не будет работать:

 dict(x.items() | y.items()) 

Для поведения типа python3 в версии 2.7 метод viewitems должен работать вместо items :

 dict(x.viewitems() | y.viewitems()) 

Я предпочитаю эту нотацию, так как кажется более естественным думать об этом как о заданной операции объединения, а не о конкатенации (как видно из названия).

Edit:

Еще пара точек для python 3. Сначала обратите внимание, что трюк dict(x, **y) не будет работать в python 3, если только клавиши в y не являются строками.

Кроме того, Raymond Hettinger Chainmap answer довольно элегантен, так как он может принимать произвольное количество dicts в качестве аргументов, но из документов , похоже, что он последовательно просматривает список всех dicts для каждого поиска:

Подсказки ищут базовые сопоставления последовательно до тех пор, пока не будет найден ключ.

Это может замедлить работу, если у вас есть много запросов в вашем приложении:

 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 

Так что примерно на порядок медленнее для поиска. Я поклонник Chainmap, но выглядит менее практичным, где может быть много поисков.

22
ответ дан beardc 09 окт. '13 в 21:09 2013-10-09 21:09

Простое решение с использованием itertools, которое сохраняет порядок (последние имеют приоритет)

 import itertools as it merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args))) 

И это использование:

 >>> 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} 
17
ответ дан reubano 04 авг. '15 в 17:54 2015-08-04 17:54

Злоупотребление, приводящее к решению одного выражения для Ответ Мэтью :

 >>> 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} 

Вы сказали, что хотите одно выражение, поэтому я злоупотреблял lambda , чтобы связать имя, и кортежи, чтобы переопределить лимитный одномерный лимит. Не стесняйтесь съеживаться.

Вы также можете сделать это, конечно, если вам не нужно его копировать:

 >>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = (x.update(y), x)[1] >>> z {'a': 1, 'b': 10, 'c': 11} 
17
ответ дан Claudiu 08 авг. '13 в 0:23 2013-08-08 00:23

В python 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) 

Из:

 {1: 1, 2: 2, 3: 4} 

Документы: https://docs.python.org/3/library/collections.html#collections.ChainMap :

15
ответ дан Skyduy 24 мая '17 в 10:24 2017-05-24 10:24

Два словаря

 def union2(dict1, dict2): return dict(list(dict1.items()) + list(dict2.items())) 

n словарей

 def union(*dicts): return dict(itertools.chain.from_iterable(dct.items() for dct in dicts)) 

sum имеет плохую производительность. См. https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

15
ответ дан Mathieu Larose 17 окт. '12 в 5:09 2012-10-17 05:09

Несмотря на то, что ответы были хороши для этого неглубокого словаря, ни один из методов, описанных здесь, на самом деле не выполняет глубокое слияние слов.

Nümunələr:

 a = { 'one': { 'depth_2': True }, 'two': True } b = { 'one': { 'extra': False } } print dict(a.items() + b.items()) 

Ожидалось бы что-то вроде этого:

 { 'one': { 'extra': False', 'depth_2': True }, 'two': True } 

Вместо этого получим следующее:

 {'two': True, 'one': {'extra': False}} 

В "одной" записи должны были быть "depth_2" и "дополнительные" как элементы внутри словаря, если это действительно было слияние.

Использование цепочки также не работает:

 from itertools import chain print dict(chain(a.iteritems(), b.iteritems())) 

Результаты в:

 {'two': True, 'one': {'extra': False}} 

Глубокое слияние, которое дал rcwesick, также создает тот же результат.

Да, это сработает, чтобы объединить образцы словарей, но ни один из них не является общим механизмом для объединения. Я обновлю это позже, когда напишу метод, который выполняет истинное слияние.

13
ответ дан Thanh Lim 04 авг. '12 в 2:36 2012-08-04 02:36

Для Python 2:

 x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items()+y.items()) print(z) 

Для Python 3:

 x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items()|y.items()) print(z) 

Он выводит результат: {'a': 1, 'c': 11, 'b': 10}

12
ответ дан Kalpesh Dusane 31 авг. '16 в 16:53 2016-08-31 16:53

Опираясь на идеи здесь и в других местах, я понял функцию:

 def merge(*dicts, **kv): return { k:v for d in list(dicts) + [kv] for k,v in d.items() } 

Использование (проверено на python 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}) 

Вместо этого вы можете использовать лямбда.

9
ответ дан Bijou Trouvaille 19 июля '13 в 8:49 2013-07-19 08:49
 from collections import Counter dict1 = {'a':1, 'b': 2} dict2 = {'b':10, 'c': 11} result = dict(Counter(dict1) + Counter(dict2)) 

Это должно решить вашу проблему.

8
ответ дан reetesh11 30 нояб. '15 в 16:04 2015-11-30 16:04

В Python 3.5 вы можете использовать unpack ** для создания нового словаря. Этот метод не был показан в прошлых ответах. Кроме того, лучше использовать {} вместо dict() . Поскольку {} - это литерал python, а dict() - вызов функции.

 dict1 = {'a':1} dict2 = {'b':2} new_dict = {**dict1, **dict2} >>>new_dict {'a':1, 'a':2} 
8
ответ дан levi 28 сент. '16 в 3:33 2016-09-28 03:33

Это можно сделать с помощью единственного понимания:

 >>> 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) } 

На мой взгляд, лучший ответ для части "одного выражения" как дополнительных функций не требуется, и он короток.

8
ответ дан RemcoGerlich 17 июля '15 в 17:47 2015-07-17 17:47
 >>> 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} 
7
ответ дан John La Rooy 13 нояб. '13 в 13:01 2013-11-13 13:01

(только для Python2.7 *, для Python3 есть более простые решения.)

Если вы не прочь импортировать стандартный библиотечный модуль, вы можете сделать

 from functools import reduce def merge_dicts(*dicts): return reduce(lambda a, d: a.update(d) or a, dicts, {}) 

(бит or a в lambda необходим, потому что dict.update всегда возвращает None при успешном завершении.)

7
ответ дан kjo 28 марта '16 в 16:13 2016-03-28 16:13

Для этого вы можете использовать toolz.merge([x, y]) .

7
ответ дан Mike Graham 18 нояб. '16 в 15:53 2016-11-18 15:53
  • 1
  • 2

Другие вопросы по меткам или Задайте вопрос