मेरे पास दो पायथन शब्दकोश हैं, और मैं एक अभिव्यक्ति लिखना चाहता हूं जो इन दो शब्दकोशों को लौटाता है, विलय (यानी संघ लेना)। update()
विधि वही होगी जो मुझे चाहिए, अगर यह एक शब्दकोश को जगह में संशोधित करने के बजाय अपना परिणाम लौटाती है।
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}
मैं उस अंतिम मर्ज किए गए शब्दकोश को z
में कैसे प्राप्त कर सकता हूं, x
में नहीं?
(अतिरिक्त स्पष्ट होने के लिए, dict.update()
की अंतिम-एक-जीत संघर्ष-प्रबंधन वह है जिसे मैं भी ढूंढ रहा हूं।)
28 जवाब
एक विकल्प:
z = x.copy()
z.update(y)
Update
"मुख्य" कार्यों में से एक नहीं है जिसका लोग बहुत अधिक उपयोग करते हैं।
(lambda z: z.update(y) or z)(x.copy())
:P . कर सकते हैं
एक और, अधिक संक्षिप्त, विकल्प:
z = dict(x, **y)
नोट: यह एक लोकप्रिय उत्तर बन गया है, लेकिन यह बताना महत्वपूर्ण है कि यदि y
में कोई गैर-स्ट्रिंग कुंजियां हैं, तो यह तथ्य कि यह बिल्कुल भी काम करता है, एक CPython का दुरुपयोग है कार्यान्वयन विवरण, और यह Python 3, या PyPy, IronPython, या Jython में काम नहीं करता है। साथ ही, Guido एक प्रशंसक नहीं है। इसलिए मैं इस तकनीक को आगे-संगत या क्रॉस-कार्यान्वयन पोर्टेबल कोड के लिए अनुशंसा नहीं कर सकता, जिसका वास्तव में मतलब है कि इसे पूरी तरह से टाला जाना चाहिए।
यह शायद एक लोकप्रिय उत्तर नहीं होगा, लेकिन आप लगभग निश्चित रूप से ऐसा नहीं करना चाहते हैं। अगर आप एक ऐसी कॉपी चाहते हैं जो मर्ज हो, तो कॉपी (या डीपकॉपी का इस्तेमाल करें, जो कि निर्भर करता है आप जो चाहते हैं उस पर) और फिर अपडेट करें। कोड की दो पंक्तियां .items() + .items() के साथ सिंगल लाइन निर्माण की तुलना में अधिक पठनीय - अधिक पाइथोनिक - हैं। स्पष्ट निहित से बेहतर है.
इसके अलावा, जब आप .items() (पायथन 3.0 से पहले) का उपयोग करते हैं, तो आप एक नई सूची बना रहे हैं जिसमें dict से आइटम शामिल हैं। यदि आपके शब्दकोश बड़े हैं, तो यह काफी अधिक है (दो बड़ी सूचियां जो मर्ज किए गए निर्देश के बनते ही फेंक दी जाएंगी)। अपडेट () अधिक कुशलता से काम कर सकता है, क्योंकि यह दूसरे आइटम-दर-आइटम के माध्यम से चल सकता है।
समय के संदर्भ में:
>>> 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 पहले दो के बीच की छोटी मंदी पठनीयता के लिए इसके लायक है। इसके अलावा, शब्दकोश निर्माण के लिए कीवर्ड तर्क केवल पायथन 2.3 में जोड़े गए थे, जबकि कॉपी () और अपडेट () पुराने संस्करणों में काम करेंगे।
अनुवर्ती उत्तर में, आपने इन दो विकल्पों के सापेक्ष प्रदर्शन के बारे में पूछा:
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)
मेरी मशीन पर, कम से कम (एक काफी सामान्य x86_64 पायथन 2.5.2 चल रहा है), वैकल्पिक z2
न केवल छोटा और सरल है, बल्कि काफी तेज भी है। आप पाइथन के साथ आने वाले timeit
मॉड्यूल का उपयोग करके इसे अपने लिए सत्यापित कर सकते हैं।
उदाहरण 1 : समरूप शब्दकोष स्वयं में 20 क्रमागत पूर्णांकों का मानचित्रण करते हैं:
% 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 या उससे अधिक के कारक से जीतता है। अलग-अलग शब्दकोश काफी भिन्न परिणाम देते प्रतीत होते हैं, लेकिन z2
हमेशा आगे निकलते प्रतीत होते हैं। (यदि आपको समान परीक्षण के लिए असंगत परिणाम मिलते हैं, तो -r
में डिफ़ॉल्ट 3 से बड़ी संख्या के साथ उत्तीर्ण होने का प्रयास करें।)
उदाहरण 2: गैर-अतिव्यापी शब्दकोश 252 लघु स्ट्रिंग्स को पूर्णांकों में मैप करते हैं और इसके विपरीत:
% 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
लगभग 10 के फ़ैक्टर से जीतता है। यह मेरी किताब में एक बहुत बड़ी जीत है!
उन दोनों की तुलना करने के बाद, मुझे आश्चर्य हुआ कि क्या z1
के खराब प्रदर्शन को दो आइटम सूचियों के निर्माण के लिए जिम्मेदार ठहराया जा सकता है, जिससे मुझे आश्चर्य हुआ कि क्या यह भिन्नता बेहतर काम कर सकती है:
from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))
कुछ त्वरित परीक्षण, उदा।
% 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
मुझे यह निष्कर्ष निकालने के लिए प्रेरित करता है कि z3
, z1
से कुछ तेज है, लेकिन लगभग z2
जितना तेज नहीं है। निश्चित रूप से सभी अतिरिक्त टाइपिंग के लायक नहीं है।
इस चर्चा में अभी भी कुछ महत्वपूर्ण याद आ रही है, जो कि दो सूचियों को मर्ज करने के "स्पष्ट" तरीके से इन विकल्पों की प्रदर्शन तुलना है: update
विधि का उपयोग करना। चीजों को भावों के साथ समान स्तर पर रखने की कोशिश करने के लिए, जिनमें से कोई भी x या y को संशोधित नहीं करता है, मैं इसे जगह में संशोधित करने के बजाय x की एक प्रति बनाने जा रहा हूं, जो निम्नानुसार है:
z0 = dict(x)
z0.update(y)
एक सामान्य परिणाम:
% 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
दूसरे शब्दों में, z0
और z2
का प्रदर्शन अनिवार्य रूप से एक जैसा लगता है। क्या आपको लगता है कि यह एक संयोग हो सकता है? मैं नही....
वास्तव में, मैं यह दावा करने के लिए इतना आगे जाऊंगा कि शुद्ध पायथन कोड के लिए इससे बेहतर कुछ करना असंभव है। और यदि आप सी एक्सटेंशन मॉड्यूल में काफी बेहतर कर सकते हैं, तो मुझे लगता है कि पाइथन लोगों को आपके कोड (या आपके दृष्टिकोण पर भिन्नता) को पायथन कोर में शामिल करने में रुचि हो सकती है। पायथन कई जगहों पर dict
का उपयोग करता है; इसके संचालन को अनुकूलित करना एक बड़ी बात है।
आप इसे इस प्रकार भी लिख सकते हैं
z0 = x.copy()
z0.update(y)
जैसा कि टोनी करता है, लेकिन (आश्चर्य की बात नहीं) अंकन में अंतर का प्रदर्शन पर कोई औसत दर्जे का प्रभाव नहीं पड़ता है। जो आपको सही लगे उसका प्रयोग करें। बेशक, वह यह बताना बिल्कुल सही है कि दो-कथन संस्करण को समझना बहुत आसान है।
items()
के योग्य नहीं है, और iteritems
मौजूद नहीं है।
पायथन 3.0 और बाद के संस्करण में, आप का उपयोग कर सकते हैं collections.ChainMap
जो एकल, अद्यतन करने योग्य दृश्य बनाने के लिए एकाधिक dicts या अन्य मैपिंग को एक साथ समूहित करता है:
>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(ChainMap({}, y, x))
>>> for k, v in z.items():
print(k, '-->', v)
a --> 1
b --> 10
c --> 11
पायथन 3.5 और बाद के संस्करण के लिए अपडेट करें: आप PEP 448< का उपयोग कर सकते हैं / ए> विस्तारित शब्दकोश पैकिंग और अनपैकिंग। यह तेज़ और आसान है:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}
पायथन 3.9 और बाद के संस्करण के लिए अपडेट: आप PEP 584 का उपयोग कर सकते हैं संघ संचालक:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x | y
{'a': 1, 'b': 10, 'c': 11}
del
को कॉल करते हैं तो चेनमैप सी उस कुंजी की पहली मैपिंग को हटा देगा।
dict
पर कास्ट कर सकते हैं, यानी: dict(ChainMap({}, y, x))
a single, updateable view
नहीं है। यह संपादन वापस किया जाना चाहिए।
मैं कुछ ऐसा ही चाहता था, लेकिन यह निर्दिष्ट करने की क्षमता के साथ कि डुप्लिकेट कुंजियों पर मूल्यों को कैसे मिला दिया गया था, इसलिए मैंने इसे हैक कर लिया (लेकिन इसका भारी परीक्षण नहीं किया)। जाहिर है यह एक एकल अभिव्यक्ति नहीं है, बल्कि यह एक एकल फ़ंक्शन कॉल है।
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
पुनरावर्ती/गहरा अद्यतन एक तानाशाही
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
प्रदर्शन:
pluto_original = {
'name': 'Pluto',
'details': {
'tail': True,
'color': 'orange'
}
}
pluto_update = {
'name': 'Pluutoo',
'details': {
'color': 'blue'
}
}
print deepupdate(pluto_original, pluto_update)
आउटपुट:
{
'name': 'Pluutoo',
'details': {
'color': 'blue',
'tail': True
}
}
संपादन के लिए धन्यवाद रेडना।
कॉपी का उपयोग न करते समय मैं जो सबसे अच्छा संस्करण सोच सकता था वह होगा:
from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))
यह dict(x.items() + y.items())
से तेज़ है लेकिन n = copy(a); n.update(b)
जितना तेज़ नहीं है, कम से कम CPython पर। यदि आप iteritems()
को items()
में बदलते हैं, तो यह संस्करण Python 3 में भी काम करता है, जो 2to3 टूल द्वारा स्वचालित रूप से किया जाता है।
व्यक्तिगत रूप से मुझे यह संस्करण सबसे अच्छा लगता है क्योंकि यह एक एकल कार्यात्मक वाक्यविन्यास में मुझे जो चाहिए वह काफी अच्छा वर्णन करता है। एकमात्र छोटी सी समस्या यह है कि यह पूरी तरह से स्पष्ट नहीं करता है कि y के मान x के मानों पर पूर्वता लेते हैं, लेकिन मुझे विश्वास नहीं है कि यह पता लगाना मुश्किल है।
पायथन 3.5 (पीईपी 448) एक अच्छे सिंटैक्स विकल्प की अनुमति देता है:
x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y}
final
# {'a': 2, 'b': 1, 'c': 2}
या और भी
final = {'a': 1, 'b': 1, **x, **y}
पायथन 3.9 में आप | . का भी उपयोग करते हैं और |= पीईपी 584 से नीचे दिए गए उदाहरण के साथ
d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
dict(x, **y)
-समाधान से बेहतर है? जैसा कि आपने (@CarlMeyer) ने अपने स्वयं के उत्तर के नोट में उल्लेख किया है (stackoverflow.com/a/39858/2798610) Guido उस समाधान को अवैध मानता है।
dict(x, **y)
को नापसंद करता है क्योंकि यह y
पर निर्भर करता है, जिसमें केवल कुंजियाँ होती हैं जो वैध कीवर्ड तर्क नाम होती हैं (जब तक कि आप CPython 2.7 का उपयोग नहीं कर रहे हैं, जहां तानाशाह निर्माता धोखा देता है)। यह आपत्ति/प्रतिबंध पीईपी 448 पर लागू नहीं होता है, जो कि **
अनपैकिंग सिंटैक्स को डिक्ट लिटरल्स के लिए सामान्यीकृत करता है। तो इस समाधान में बिना किसी नुकसान के dict(x, **y)
के समान ही संक्षिप्तीकरण है।
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z
दोनों शब्दकोशों ('बी') में चाबियों वाले आइटम के लिए, आप यह नियंत्रित कर सकते हैं कि कौन सा अंतिम आउटपुट में समाप्त होता है।
जबकि प्रश्न का उत्तर पहले ही कई बार दिया जा चुका है, समस्या का यह सरल समाधान अभी तक सूचीबद्ध नहीं किया गया है।
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)
यह ऊपर बताए गए z0 और दुष्ट z2 जितना तेज़ है, लेकिन समझने और बदलने में आसान है।
z4 = {}
को खो दें और अगली पंक्ति को z4 = x.copy()
में बदल दें - केवल अच्छे कोड से बेहतर अनावश्यक चीजें नहीं करता है (जो इसे और भी अधिक पठनीय और रखरखाव योग्य बनाता है)।
def dict_merge(a, b):
c = a.copy()
c.update(b)
return c
new = dict_merge(old, extras)
इस तरह के अस्पष्ट और संदिग्ध उत्तरों के बीच, यह चमकदार उदाहरण पायथन में डिक्ट्स को मर्ज करने का एकमात्र अच्छा तरीका है, जिसे तानाशाह द्वारा जीवन के लिए समर्थन दिया गया है ग्यूडो वैन रोसुम स्वयं! किसी और ने इसका आधा सुझाव दिया, लेकिन इसे किसी समारोह में नहीं रखा।
print dict_merge(
{'color':'red', 'model':'Mini'},
{'model':'Ferrari', 'owner':'Carl'})
देता है:
{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
अगर आपको लगता है कि लंबोदर दुष्ट हैं तो आगे न पढ़ें। अनुरोध के अनुसार, आप एक अभिव्यक्ति के साथ तेज और स्मृति-कुशल समाधान लिख सकते हैं:
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}
जैसा कि ऊपर सुझाव दिया गया है, दो पंक्तियों का उपयोग करना या फ़ंक्शन लिखना शायद जाने का एक बेहतर तरीका है।
पाइथोनिक हो। एक समझ का उपयोग करें:
z={i:d[i] for d in [x,y] for i in d}
>>> print z
{'a': 1, 'c': 11, 'b': 10}
def dictmerge(*args): return {i:d[i] for d in args for i in d}
z={k: v for d in (x, y) for k, v in d.items()}
Python3 में, items
विधि अब कोई सूची नहीं देता, बल्कि एक दृश्य देता है, जो एक सेट की तरह कार्य करता है। इस मामले में आपको सेट यूनियन लेने की आवश्यकता होगी क्योंकि +
के साथ काम करने से काम नहीं चलेगा:
dict(x.items() | y.items())
संस्करण 2.7 में python3 जैसे व्यवहार के लिए, viewitems
विधि को items
के स्थान पर काम करना चाहिए:
dict(x.viewitems() | y.viewitems())
मैं वैसे भी इस संकेतन को पसंद करता हूं क्योंकि इसे संयोजन के बजाय एक सेट यूनियन ऑपरेशन के रूप में सोचना अधिक स्वाभाविक लगता है (जैसा कि शीर्षक से पता चलता है)।
संपादित करें:
अजगर 3 के लिए कुछ और अंक। सबसे पहले, ध्यान दें कि dict(x, **y)
चाल अजगर 3 में तब तक काम नहीं करेगी जब तक कि y
में कुंजियाँ तार न हों।
साथ ही, रेमंड हेटिंगर का चैनमैप answer बहुत सुंदर है, क्योंकि यह तर्कों के रूप में मनमाने ढंग से संख्याओं को ले सकता है, लेकिन दस्तावेज़ों से ऐसा लगता है कि यह क्रमिक रूप से प्रत्येक लुकअप के लिए सभी 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
तो लुकअप के लिए परिमाण धीमी गति के क्रम के बारे में। मैं चैनमैप का प्रशंसक हूं, लेकिन जहां कई लुकअप हो सकते हैं, वहां कम व्यावहारिक लगता है।
दुरुपयोग के कारण मैथ्यू का उत्तर के लिए एक-अभिव्यक्ति समाधान:
>>> 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
का दुरुपयोग किया, और लैम्ब्डा की वन-एक्सप्रेशन सीमा को ओवरराइड करने के लिए tuples का दुरुपयोग किया। क्रिंग करने के लिए स्वतंत्र महसूस करें।
यदि आप इसे कॉपी करने की परवाह नहीं करते हैं तो आप इसे निश्चित रूप से भी कर सकते हैं:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
दो शब्दकोश
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 -नॉट-टू-फ्लैटन-ए-लिस्ट-ऑफ-लिस्ट्स-इन-पायथन/
हालांकि इस उथले शब्दकोश के लिए उत्तर अच्छे थे, लेकिन यहां परिभाषित कोई भी विधि वास्तव में एक गहरी शब्दकोश मर्ज नहीं करती है।
उदाहरण अनुसरण करते हैं:
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}}
'एक' प्रविष्टि में 'गहराई_2' और 'अतिरिक्त' अपने शब्दकोश के अंदर आइटम के रूप में होना चाहिए था अगर यह वास्तव में एक विलय था।
श्रृंखला का उपयोग करना भी काम नहीं करता है:
from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))
का परिणाम:
{'two': True, 'one': {'extra': False}}
Rcwesick ने जो गहरा मर्ज दिया है, वह भी वही परिणाम देता है।
हां, यह नमूना शब्दकोशों को मर्ज करने के लिए काम करेगा, लेकिन उनमें से कोई भी विलय करने के लिए एक सामान्य तंत्र नहीं है। एक बार जब मैं एक वास्तविक विलय करने वाली विधि लिखता हूं तो मैं इसे बाद में अपडेट कर दूंगा।
यहाँ और अन्य जगहों पर विचारों को आकर्षित करते हुए मैंने एक फ़ंक्शन को समझा है:
def merge(*dicts, **kv):
return { k:v for d in list(dicts) + [kv] for k,v in d.items() }
उपयोग (पायथन 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})
आप इसके बजाय लैम्ब्डा का उपयोग कर सकते हैं।
मेरे पास आज तक सूचीबद्ध समाधानों के साथ समस्या यह है कि, मर्ज किए गए शब्दकोश में, कुंजी "बी" का मान 10 है, लेकिन, मेरे सोचने के तरीके के लिए, यह 12 होना चाहिए। उस प्रकाश में, मैं निम्नलिखित प्रस्तुत करता हूं:
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
परिणाम:
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}
cytoolz.merge_with
(toolz.readthedocs में हो सकती है .io/en/latest/…)
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))
इससे आपकी समस्या का समाधान हो जाना चाहिए।
+
के बजाय काउंटर के .update()
का उपयोग करने की अनुशंसा करूंगा। ऐसा इसलिए है, क्योंकि यदि योग किसी भी कुंजी के लिए 0 के मान का परिणाम देता है, तो काउंटर उसे हटा देगा।
(केवल Python2.7* के लिए; Python3* के लिए सरल समाधान हैं।)
यदि आप एक मानक पुस्तकालय मॉड्यूल आयात करने के खिलाफ नहीं हैं, तो आप कर सकते हैं
from functools import reduce
def merge_dicts(*dicts):
return reduce(lambda a, d: a.update(d) or a, dicts, {})
(lambda
में or a
बिट आवश्यक है क्योंकि dict.update
हमेशा सफलता पर None
लौटाता है।)
>>> 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}
x
को अधिलेखित कर देती है। अगर x
एक फ़ंक्शन तर्क है तो यह काम नहीं करेगा (देखें उदाहरण)
यह इतना मूर्खतापूर्ण है कि .update
कुछ भी नहीं लौटाता।
मैं समस्या को हल करने के लिए बस एक साधारण सहायक फ़ंक्शन का उपयोग करता हूं:
def merge(dict1,*dicts):
for dict2 in dicts:
dict1.update(dict2)
return dict1
उदाहरण:
merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2) # this one returns a new copy
अगर आपको x
को बदलने में कोई आपत्ति नहीं है,
x.update(y) or x
सरल, पठनीय, प्रदर्शनकारी। आप जानते हैं update()
हमेशा None
लौटाते हैं, जो एक गलत मान है। अतः उपरोक्त व्यंजक हमेशा अद्यतन करने के बाद x
का मूल्यांकन करेगा।
मानक पुस्तकालय में अधिकांश परिवर्तनशील विधियाँ (जैसे .update()
) सम्मेलन द्वारा None
लौटाती हैं, इसलिए इस प्रकार का पैटर्न उन पर भी काम करेगा। हालाँकि, यदि आप एक तानाशाही उपवर्ग या किसी अन्य विधि का उपयोग कर रहे हैं जो इस सम्मेलन का पालन नहीं करता है, तो or
अपना बायाँ संकार्य वापस कर सकता है, जो वह नहीं हो सकता जो आप चाहते हैं। इसके बजाय, आप एक टपल डिस्प्ले और इंडेक्स का उपयोग कर सकते हैं, जो इस बात की परवाह किए बिना काम करता है कि पहला तत्व क्या मूल्यांकन करता है (हालाँकि यह उतना सुंदर नहीं है):
(x.update(y), x)[-1]
यदि आपके पास अभी तक एक वेरिएबल में x
नहीं है, तो आप असाइनमेंट स्टेटमेंट का उपयोग किए बिना स्थानीय बनाने के लिए lambda
का उपयोग कर सकते हैं। यह lambda
को लेट एक्सप्रेशन के रूप में उपयोग करने के बराबर है, जो कार्यात्मक भाषाओं में एक सामान्य तकनीक है, लेकिन शायद अनपायथनिक है।
(lambda x: x.update(y) or x)({'a': 1, 'b': 2})
हालांकि यह नए वालरस ऑपरेटर (केवल पायथन 3.8+) के निम्नलिखित उपयोग से अलग नहीं है,
(x := {'a': 1, 'b': 2}).update(y) or x
खासकर यदि आप एक डिफ़ॉल्ट तर्क का उपयोग करते हैं:
(lambda x={'a': 1, 'b': 2}: x.update(y) or x)()
अगर आप एक कॉपी चाहते हैं, तो PEP 584 स्टाइल x | y
3.9+ पर सबसे पाइथोनिक है। अगर आपको पुराने संस्करणों का समर्थन करना चाहिए, PEP 448 शैली {**x, **y}
3.5+ के लिए सबसे आसान है। लेकिन अगर यह आपके (और भी पुराने) पायथन संस्करण में उपलब्ध नहीं है, तो लेट एक्सप्रेशन पैटर्न यहां भी काम करता है।
(lambda z=x.copy(): z.update(y) or z)()
(यह निश्चित रूप से, लगभग (z := x.copy()).update(y) or z
के बराबर है, लेकिन यदि आपका पायथन संस्करण उसके लिए काफी नया है, तो पीईपी 448 शैली उपलब्ध होगी।)
एक तानाशाही समझ का उपयोग करते हुए, आप कर सकते हैं
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dc = {xi:(x[xi] if xi not in list(y.keys())
else y[xi]) for xi in list(x.keys())+(list(y.keys()))}
देता है
>>> dc
{'a': 1, 'c': 11, 'b': 10}
समझ में if else
के सिंटैक्स पर ध्यान दें
{ (some_key if condition else default_key):(something_if_true if condition
else something_if_false) for key, value in dict_.items() }
... in y
के बजाय ... in list(y.keys())
का उपयोग करना पागलपन है।
मुझे पता है कि यह वास्तव में प्रश्नों की बारीकियों ("एक लाइनर") में फिट नहीं है, लेकिन चूंकि ऊपर दिए गए उत्तरों में से कोई भी इस दिशा में नहीं गया, जबकि बहुत सारे उत्तरों ने प्रदर्शन के मुद्दे को संबोधित किया, मुझे लगा मुझे अपने विचारों का योगदान देना चाहिए।
उपयोग के मामले के आधार पर दिए गए इनपुट शब्दकोशों का "वास्तविक" मर्ज किया गया शब्दकोश बनाना आवश्यक नहीं हो सकता है। एक दृश्य जो ऐसा करता है कई मामलों में पर्याप्त हो सकता है, i. इ। एक ऑब्जेक्ट जो मर्ज किए गए शब्दकोश की तरह पसंद काम करता है, उसकी पूरी तरह से गणना किए बिना होगा। मर्ज किए गए शब्दकोश का एक आलसी संस्करण, इसलिए बोलने के लिए।
पायथन में, यह अपेक्षाकृत सरल है और मेरी पोस्ट के अंत में दिखाए गए कोड के साथ किया जा सकता है। यह दिया गया है, मूल प्रश्न का उत्तर होगा:
z = MergeDict(x, y)
इस नई वस्तु का उपयोग करते समय, यह एक मर्ज किए गए शब्दकोश की तरह व्यवहार करेगा, लेकिन मूल शब्दकोशों को अछूता छोड़ते हुए इसमें निरंतर निर्माण समय और निरंतर स्मृति पदचिह्न होगा। प्रस्तावित अन्य समाधानों की तुलना में इसे बनाना सस्ता है।
बेशक, यदि आप परिणाम का बहुत अधिक उपयोग करते हैं, तो आप किसी बिंदु पर उस सीमा तक पहुंच जाएंगे जहां वास्तविक मर्ज किए गए शब्दकोश को बनाना सबसे तेज़ समाधान होता। जैसा कि मैंने कहा, यह आपके उपयोग के मामले पर निर्भर करता है।
यदि आपने कभी महसूस किया है कि आप एक वास्तविक मर्ज किए गए dict
को पसंद करेंगे, तो dict(z)
पर कॉल करने से यह उत्पादन होगा (लेकिन निश्चित रूप से अन्य समाधानों की तुलना में अधिक महंगा है, इसलिए यह केवल ध्यान देने योग्य है)।
आप इस वर्ग का उपयोग एक प्रकार की कॉपी-ऑन-राइट डिक्शनरी बनाने के लिए भी कर सकते हैं:
a = { 'x': 3, 'y': 4 }
b = MergeDict(a) # we merge just one dict
b['x'] = 5
print b # will print {'x': 5, 'y': 4}
print a # will print {'y': 4, 'x': 3}
यहाँ MergeDict
का सीधा-सीधा कोड है:
class MergeDict(object):
def __init__(self, *originals):
self.originals = ({},) + originals[::-1] # reversed
def __getitem__(self, key):
for original in self.originals:
try:
return original[key]
except KeyError:
pass
raise KeyError(key)
def __setitem__(self, key, value):
self.originals[0][key] = value
def __iter__(self):
return iter(self.keys())
def __repr__(self):
return '%s(%s)' % (
self.__class__.__name__,
', '.join(repr(original)
for original in reversed(self.originals)))
def __str__(self):
return '{%s}' % ', '.join(
'%r: %r' % i for i in self.iteritems())
def iteritems(self):
found = set()
for original in self.originals:
for k, v in original.iteritems():
if k not in found:
yield k, v
found.add(k)
def items(self):
return list(self.iteritems())
def keys(self):
return list(k for k, _ in self.iteritems())
def values(self):
return list(v for _, v in self.iteritems())
ChainMap
नामक एक वर्ग को संदर्भित करते हैं जो केवल पायथन 3 में उपलब्ध है और जो कमोबेश वही करता है जो मेरा कोड करता है। सब कुछ ध्यान से नहीं पढ़ने के लिए मुझ पर शर्म आती है। लेकिन यह देखते हुए कि यह केवल पायथन 3 के लिए मौजूद है, कृपया मेरे उत्तर को पायथन 2 उपयोगकर्ताओं के लिए योगदान के रूप में लें ;-)
पायथन 3.9 में नया: का प्रयोग करें यूनियन ऑपरेटर (|
) dict
को set
s के समान मर्ज करने के लिए:
>>> d = {'a': 1, 'b': 2}
>>> e = {'a': 9, 'c': 3}
>>> d | e
{'a': 9, 'b': 2, 'c': 3}
मेल खाने वाली कुंजियों के लिए, दाएं dict
को प्राथमिकता दी जाती है।
यह |=
के लिए एक dict
को इन-प्लेस संशोधित करने के लिए भी काम करता है:
>>> e |= d # e = e | d
>>> e
{'a': 1, 'c': 3, 'b': 2}
संबंधित सवाल
नए सवाल
python
पायथन एक बहु-प्रतिमान है, गतिशील रूप से टाइप किया हुआ, बहुउद्देशीय प्रोग्रामिंग भाषा है। यह एक साफ और एक समान वाक्यविन्यास सीखने, समझने और उपयोग करने के लिए त्वरित होने के लिए डिज़ाइन किया गया है। कृपया ध्यान दें कि अजगर 2 आधिकारिक तौर पर 01-01-2020 के समर्थन से बाहर है। फिर भी, संस्करण-विशिष्ट पायथन सवालों के लिए, [अजगर -२.०] या [अजगर -३.x] टैग जोड़ें। पायथन वेरिएंट (जैसे, ज्योथन, PyPy) या लाइब्रेरी (उदा।, पांडस और न्यूमपी) का उपयोग करते समय, कृपया इसे टैग में शामिल करें।