दो पायथन शब्दकोशों में निहित कुंजियों में अंतर की गणना करें


171

मान लीजिए कि मेरे पास दो पायथन शब्दकोश हैं - dictAऔर dictB। मुझे यह पता लगाने की ज़रूरत है कि क्या कोई कुंजी है जो मौजूद हैं, dictBलेकिन अंदर नहीं dictA। इसके बारे में जाने का सबसे तेज़ तरीका क्या है?

क्या मुझे शब्दकोश कुंजियों को एक सेट में बदलना चाहिए और फिर जाना चाहिए?

आपके विचार जानने के इच्छुक हैं ...


आपकी प्रतिक्रियाओं के लिए धन्यवाद।

मेरे प्रश्न को ठीक से न बताने के लिए क्षमा याचना। मेरा परिदृश्य इस तरह है - मेरे पास एक dictAऐसा ही dictBहो सकता है या उसकी तुलना में कुछ चाबियाँ गायब हो सकती हैं dictBया फिर कुछ कुंजी का मूल्य भिन्न हो सकता है जिसे dictAकुंजी के मूल्य पर सेट किया जाना है ।

समस्या यह है कि डिक्शनरी का कोई मानक नहीं है और इसमें ऐसे मूल्य हो सकते हैं जो तानाशाही से मुक्त हो सकते हैं।

कहो

dictA={'key1':a, 'key2':b, 'key3':{'key11':cc, 'key12':dd}, 'key4':{'key111':{....}}}
dictB={'key1':a, 'key2:':newb, 'key3':{'key11':cc, 'key12':newdd, 'key13':ee}.......

इसलिए 'की 2' वैल्यू को नए मूल्य पर रीसेट करना होगा और 'की -13' को डिक्टेट के अंदर जोड़ना होगा। कुंजी मान का कोई निश्चित प्रारूप नहीं है। यह एक साधारण मूल्य या एक तानाशाह या एक तानाशाह का हो सकता है।

जवाबों:


234

आप कुंजी पर सेट ऑपरेशन का उपयोग कर सकते हैं:

diff = set(dictb.keys()) - set(dicta.keys())

यहां सभी संभावनाओं को खोजने के लिए एक वर्ग है: क्या जोड़ा गया था, क्या हटाया गया था, कौन-से कुंजी-मूल्य जोड़े समान हैं, और कौन-से कुंजी-मूल्य जोड़े बदले गए हैं।

class DictDiffer(object):
    """
    Calculate the difference between two dictionaries as:
    (1) items added
    (2) items removed
    (3) keys same in both but changed values
    (4) keys same in both and unchanged values
    """
    def __init__(self, current_dict, past_dict):
        self.current_dict, self.past_dict = current_dict, past_dict
        self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys())
        self.intersect = self.set_current.intersection(self.set_past)
    def added(self):
        return self.set_current - self.intersect 
    def removed(self):
        return self.set_past - self.intersect 
    def changed(self):
        return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o])
    def unchanged(self):
        return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])

यहाँ कुछ नमूना आउटपुट है:

>>> a = {'a': 1, 'b': 1, 'c': 0}
>>> b = {'a': 1, 'b': 2, 'd': 0}
>>> d = DictDiffer(b, a)
>>> print "Added:", d.added()
Added: set(['d'])
>>> print "Removed:", d.removed()
Removed: set(['c'])
>>> print "Changed:", d.changed()
Changed: set(['b'])
>>> print "Unchanged:", d.unchanged()
Unchanged: set(['a'])

गिथब रेपो के रूप में उपलब्ध: https://github.com/hughdbrown/dictdiffer


3
स्मार्ट समाधान, धन्यवाद! मैंने यह जाँच करके नेस्टड डाइक्ट्स के साथ काम किया है कि क्या बदले हुए या अपरिवर्तित मूल्य प्रमुख उदाहरण हैं और एक पुनरावर्ती फ़ंक्शन को कॉल करके उन्हें आपकी कक्षा का उपयोग करने के लिए फिर से जाँच करें।
एजेजे

1
@AJJ मैं उस कार्यान्वयन को देखना पसंद करूंगा।
urschrei

1
कैसे के बारे में def update(self, new_dict): self.__init__(new_dict, self.current_dict)या जैसे आप एक रोलिंग तुलना कर सकते हैं
निक टी

कुछ टिप्पणी: DictDifferकक्षा एक स्टेटलेस क्लास है और एक फ़ंक्शन हो सकती है। changedऔर unchangedमान एक ही पाश में की जा सकती है। यह दो कार्य एक के listबजाय वापस आ सकता है setजो निश्चित रूप से कम महंगा है। गहरी तुलना के लिए, आप इकाई परीक्षण ढांचे पर एक नज़र डाल सकते हैं: docs.python.org/2/library/unittest.html , assertDictEqualस्रोत कोड में विधि का पालन करें ।
लॉरेंट LAPORTE

1
एफडब्ल्यूआईडब्ल्यू, set(dictb)शायद इससे बेहतर है set(dictb.keys())
एमजीलसन

60

यदि आप अंतर को पुनरावर्ती चाहते हैं, तो मैंने अजगर के लिए एक पैकेज लिखा है: https://github.com/seperman/deepdiff

स्थापना

PyPi से स्थापित करें:

pip install deepdiff

उदाहरण उपयोग

आयात कर रहा है

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

वही वस्तु खाली लौटती है

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

एक आइटम का प्रकार बदल गया है

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

किसी आइटम का मान बदल गया है

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

आइटम जोड़ा गया और / या हटा दिया गया

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

स्ट्रिंग अंतर

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

स्ट्रिंग अंतर २

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

प्रकार बदलें

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

सूची का अंतर

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

सूची अंतर 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

आदेश या डुप्लिकेट की अनदेखी अंतर सूची: (ऊपर के रूप में एक ही शब्दकोश के साथ)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

उस सूची में शब्दकोश शामिल हैं:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

सेट:

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

नामित टुपल्स:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

कस्टम ऑब्जेक्ट:

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

ऑब्जेक्ट विशेषता जोड़ी गई:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

इसके लिए शुक्रिया! बस मेरी परियोजना पर लागू, महान काम करता है!
gtalarico

1
@gtalarico मदद करने के लिए खुश! आपके नम्र शब्दों के लिए धन्यवाद!
सेपरमैन

क्या सूची क्रम के अंतर को अनदेखा करने का कोई विकल्प है ? क्योंकि मेरे आवेदन के बारे में परवाह नहीं है।
लेई यांग

अच्छा प्रोजेक्ट, मेरी तरफ से न्यूनतम प्रयास के साथ सभी काम किया। धन्यवाद!
स्टानिस्लाव त्सेपा

@ लेईयांग हां आप सेट कर सकते हैं ignore_order=True। आप डॉक्स को deepdiff.readthedocs.io/en/latest/diff.html
19

18

सुनिश्चित नहीं है कि इसका "तेज" है या नहीं, लेकिन सामान्य रूप से, कोई भी ऐसा कर सकता है

dicta = {"a":1,"b":2,"c":3,"d":4}
dictb = {"a":1,"d":2}
for key in dicta.keys():
    if not key in dictb:
        print key

आपको स्वैप करना होगा dictaऔर dictbचूंकि वह जानना चाहता है कि उस की चाबी dictbअंदर नहीं है dicta
गम्बू

2
for key in dicta.keys():=>for key in dicta:
जीन फ़्राँस्वा Fabre

15

जैसा कि एलेक्स मार्टेली ने लिखा है, यदि आप बस यह जांचना चाहते हैं कि क्या B की कोई कुंजी A में नहीं है, any(True for k in dictB if k not in dictA) तो जाने का रास्ता होगा।

गुम होने वाली कुंजियों को खोजने के लिए:

diff = set(dictB)-set(dictA) #sets

C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA =    
dict(zip(range(1000),range
(1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=set(dictB)-set(dictA)"
10000 loops, best of 3: 107 usec per loop

diff = [ k for k in dictB if k not in dictA ] #lc

C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA = 
dict(zip(range(1000),range
(1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=[ k for k in dictB if
k not in dictA ]"
10000 loops, best of 3: 95.9 usec per loop

तो उन दो समाधान एक ही गति बहुत ज्यादा हैं।


8
यह अधिक समझ में आता है:any(k not in dictA for k in dictB)
ह्यूग्डब्रोन

13

यदि आप वास्तव में वही कहते हैं जो आप कहते हैं (कि आपको केवल बी में "आईएफ" की कोई कुंजी है या नहीं, तो यह पता लगाने की आवश्यकता है कि नहीं, जो नहीं हो सकता है अगर वे किसी भी हो), तो सबसे तेज़ तरीका होना चाहिए:

if any(True for k in dictB if k not in dictA): ...

यदि आपको वास्तव में WHICH KEYS, यदि कोई है, तो B में है और A में नहीं है, और केवल "IF" नहीं है, तो ऐसी कुंजियाँ हैं, तो मौजूदा उत्तर काफी उपयुक्त हैं (लेकिन मैं भविष्य के प्रश्नों में अधिक सटीक सुझाव देता हूँ वास्तव में तुम्हारा क्या मतलब है ;-)



8

Hughdbrown द्वारा शीर्ष उत्तर सेट अंतर का उपयोग करने का सुझाव देता है, जो निश्चित रूप से सबसे अच्छा तरीका है:

diff = set(dictb.keys()) - set(dicta.keys())

इस कोड के साथ समस्या यह है कि यह केवल दो सेट बनाने के लिए दो सूचियों का निर्माण करता है, इसलिए यह 4N समय और 2N स्थान बर्बाद कर रहा है। यह भी थोड़ा और अधिक जटिल होने की आवश्यकता है।

आमतौर पर, यह एक बड़ी बात नहीं है, लेकिन अगर यह है:

diff = dictb.keys() - dicta

अजगर २

पायथन 2 में, keys()कुंजियों की एक सूची देता है, न कि KeysView। इसलिए आपको viewkeys()सीधे पूछना होगा ।

diff = dictb.viewkeys() - dicta

दोहरे संस्करण 2.7 / 3.x कोड के लिए, आप उम्मीद कर रहे हैं कि आप sixइसी तरह का प्रयोग कर रहे हैं या कुछ इसी तरह का उपयोग कर सकते हैं six.viewkeys(dictb):

diff = six.viewkeys(dictb) - dicta

2.4-2.6 में, नहीं है KeysView। लेकिन आप कम से कम 4N से N तक की लागत में कटौती कर सकते हैं ताकि एक सूची बनाने के बजाए सीधे अपने itter से बाहर सेट करें:

diff = set(dictb) - dicta

आइटम

मेरे पास एक तानाशाह है जो तानाशाह के समान हो सकता है या हो सकता है कि कुछ कुंजियां गायब हो जाएं जैसे कि तानाशाह की तुलना में या फिर कुछ चाबियों का मूल्य अलग हो सकता है

इसलिए आपको वास्तव में कुंजियों की तुलना करने की आवश्यकता नहीं है, लेकिन आइटम। एक ItemsViewकेवल एक है Setअगर मूल्यों, hashable हैं तार की तरह। यदि वे हैं, तो यह आसान है:

diff = dictb.items() - dicta.items()

पुनरावर्ती भिन्न

हालांकि सवाल सीधे एक पुनरावर्ती अंतर के लिए नहीं पूछ रहा है, उदाहरण के कुछ मान dicts हैं, और ऐसा प्रतीत होता है कि अपेक्षित आउटपुट पुनरावर्ती रूप से भिन्न होता है। यहाँ पहले से ही कई उत्तर हैं जो यह दिखाते हैं कि कैसे करना है।


2018 से निश्चित उत्तर।
जीन-फ्रांकोइस फेबरे

@ जीन-फ्रांस्वा
फाबरे

कुछ लोगों को 2.6 के साथ फंस रहे हैं
जीन फ़्राँस्वा Fabre

5

इस तर्क के बारे में स्टैकओवरफ्लो में एक और सवाल है और मुझे यह स्वीकार करना होगा कि एक सरल समाधान समझाया गया है: अजगर का डेटाडिफ पुस्तकालय दो शब्दकोशों के बीच के अंतर को प्रिंट करने में मदद करता है।


3

यहां एक तरीका है जो काम करेगा, उन कुंजियों की अनुमति देता है जो मूल्यांकन करते हैं False, और फिर भी यदि संभव हो तो जल्दी बाहर आने के लिए एक जनरेटर अभिव्यक्ति का उपयोग करता है। यह असाधारण सुंदर नहीं है, हालांकि।

any(map(lambda x: True, (k for k in b if k not in a)))

संपादित करें:

THC4k ने एक अन्य उत्तर पर मेरी टिप्पणी का उत्तर पोस्ट किया। यहाँ ऊपर करने के लिए एक बेहतर, सुंदर तरीका है:

any(True for k in b if k not in a)

यकीन नहीं होता कि कैसे कभी मेरे मन को पार नहीं किया ...


इस पहले एलेक्स मार्टेली जवाब के रूप में एक ही जवाब है
जीन फ़्राँस्वा Fabre

यह अभी है। जब मैंने इसे (नौ साल पहले, lol) पोस्ट किया था, तो पहले वाला उत्तर थाany(k for k in dictB if k not in dictA) लोल) वही जो (फाल्सी कीज़ के लिए) समान नहीं है। संपादन इतिहास / टाइमस्टैम्प की जाँच करें।
स्टीव लोश

3

यह एक पुराना सवाल है और मुझे जो कुछ भी चाहिए उससे थोड़ा कम ही पूछता है, इसलिए यह जवाब वास्तव में इस सवाल से ज्यादा हल करता है। इस प्रश्न के उत्तर से मुझे निम्नलिखित हल करने में मदद मिली:

  1. (पूछा) दो शब्दकोशों के बीच अंतर रिकॉर्ड करें
  2. # 1 से आधार शब्दकोश में अंतर मिलाएं
  3. (पूछा गया) दो शब्दकोशों के बीच अंतर करें (शब्दकोश # 2 का इलाज करें जैसे कि यह एक अलग शब्दकोश हो)
  4. आइटम आंदोलनों के साथ-साथ परिवर्तनों का पता लगाने का प्रयास करें
  5. (पूछा) यह सब पुनरावृत्ति करो

यह सब JSON के साथ संयुक्त एक बहुत शक्तिशाली विन्यास भंडारण समर्थन के लिए बनाता है।

समाधान ( जीथुब पर भी ):

from collections import OrderedDict
from pprint import pprint


class izipDestinationMatching(object):
    __slots__ = ("attr", "value", "index")

    def __init__(self, attr, value, index):
        self.attr, self.value, self.index = attr, value, index

    def __repr__(self):
        return "izip_destination_matching: found match by '%s' = '%s' @ %d" % (self.attr, self.value, self.index)


def izip_destination(a, b, attrs, addMarker=True):
    """
    Returns zipped lists, but final size is equal to b with (if shorter) a padded with nulls
    Additionally also tries to find item reallocations by searching child dicts (if they are dicts) for attribute, listed in attrs)
    When addMarker == False (patching), final size will be the longer of a, b
    """
    for idx, item in enumerate(b):
        try:
            attr = next((x for x in attrs if x in item), None)  # See if the item has any of the ID attributes
            match, matchIdx = next(((orgItm, idx) for idx, orgItm in enumerate(a) if attr in orgItm and orgItm[attr] == item[attr]), (None, None)) if attr else (None, None)
            if match and matchIdx != idx and addMarker: item[izipDestinationMatching] = izipDestinationMatching(attr, item[attr], matchIdx)
        except:
            match = None
        yield (match if match else a[idx] if len(a) > idx else None), item
    if not addMarker and len(a) > len(b):
        for item in a[len(b) - len(a):]:
            yield item, item


def dictdiff(a, b, searchAttrs=[]):
    """
    returns a dictionary which represents difference from a to b
    the return dict is as short as possible:
      equal items are removed
      added / changed items are listed
      removed items are listed with value=None
    Also processes list values where the resulting list size will match that of b.
    It can also search said list items (that are dicts) for identity values to detect changed positions.
      In case such identity value is found, it is kept so that it can be re-found during the merge phase
    @param a: original dict
    @param b: new dict
    @param searchAttrs: list of strings (keys to search for in sub-dicts)
    @return: dict / list / whatever input is
    """
    if not (isinstance(a, dict) and isinstance(b, dict)):
        if isinstance(a, list) and isinstance(b, list):
            return [dictdiff(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs)]
        return b
    res = OrderedDict()
    if izipDestinationMatching in b:
        keepKey = b[izipDestinationMatching].attr
        del b[izipDestinationMatching]
    else:
        keepKey = izipDestinationMatching
    for key in sorted(set(a.keys() + b.keys())):
        v1 = a.get(key, None)
        v2 = b.get(key, None)
        if keepKey == key or v1 != v2: res[key] = dictdiff(v1, v2, searchAttrs)
    if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
    return res


def dictmerge(a, b, searchAttrs=[]):
    """
    Returns a dictionary which merges differences recorded in b to base dictionary a
    Also processes list values where the resulting list size will match that of a
    It can also search said list items (that are dicts) for identity values to detect changed positions
    @param a: original dict
    @param b: diff dict to patch into a
    @param searchAttrs: list of strings (keys to search for in sub-dicts)
    @return: dict / list / whatever input is
    """
    if not (isinstance(a, dict) and isinstance(b, dict)):
        if isinstance(a, list) and isinstance(b, list):
            return [dictmerge(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs, False)]
        return b
    res = OrderedDict()
    for key in sorted(set(a.keys() + b.keys())):
        v1 = a.get(key, None)
        v2 = b.get(key, None)
        #print "processing", key, v1, v2, key not in b, dictmerge(v1, v2)
        if v2 is not None: res[key] = dictmerge(v1, v2, searchAttrs)
        elif key not in b: res[key] = v1
    if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
    return res

2

क्या के बारे में standart (तुलना पूर्ण वस्तु)

PyDev-> नया PyDev मॉड्यूल-> मॉड्यूल: एकतरफा

import unittest


class Test(unittest.TestCase):


    def testName(self):
        obj1 = {1:1, 2:2}
        obj2 = {1:1, 2:2}
        self.maxDiff = None # sometimes is usefull
        self.assertDictEqual(d1, d2)

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']

    unittest.main()

यह बहुत अच्छा है यदि आपके पास बहुत बड़ा नेस्टेड शब्दकोश है और आप हर चीज़ की तुलना अंदर करना चाहते हैं और अंतर देखना चाहते हैं। धन्यवाद!
मैथ्यू Moisen

2

यदि पायथन: 2.7 पर:

# update different values in dictB
# I would assume only dictA should be updated,
# but the question specifies otherwise

for k in dictA.viewkeys() & dictB.viewkeys():
    if dictA[k] != dictB[k]:
        dictB[k]= dictA[k]

# add missing keys to dictA

dictA.update( (k,dictB[k]) for k in dictB.viewkeys() - dictA.viewkeys() )

1

यहां 2 शब्दकोशों की गहरी तुलना के लिए एक समाधान दिया गया है:

def compareDictKeys(dict1, dict2):
  if type(dict1) != dict or type(dict2) != dict:
      return False

  keys1, keys2 = dict1.keys(), dict2.keys()
  diff = set(keys1) - set(keys2) or set(keys2) - set(keys1)

  if not diff:
      for key in keys1:
          if (type(dict1[key]) == dict or type(dict2[key]) == dict) and not compareDictKeys(dict1[key], dict2[key]):
              diff = True
              break

  return not diff

1

यहाँ एक समाधान है जो दो से अधिक dicts की तुलना कर सकता है:

def diff_dict(dicts, default=None):
    diff_dict = {}
    # add 'list()' around 'd.keys()' for python 3 compatibility
    for k in set(sum([d.keys() for d in dicts], [])):
        # we can just use "values = [d.get(k, default) ..." below if 
        # we don't care that d1[k]=default and d2[k]=missing will
        # be treated as equal
        if any(k not in d for d in dicts):
            diff_dict[k] = [d.get(k, default) for d in dicts]
        else:
            values = [d[k] for d in dicts]
            if any(v != values[0] for v in values):
                diff_dict[k] = values
    return diff_dict

उपयोग उदाहरण:

import matplotlib.pyplot as plt
diff_dict([plt.rcParams, plt.rcParamsDefault, plt.matplotlib.rcParamsOrig])

1

दो शब्दकोशों के बीच सममित अंतर का मेरा नुस्खा:

def find_dict_diffs(dict1, dict2):
    unequal_keys = []
    unequal_keys.extend(set(dict1.keys()).symmetric_difference(set(dict2.keys())))
    for k in dict1.keys():
        if dict1.get(k, 'N\A') != dict2.get(k, 'N\A'):
            unequal_keys.append(k)
    if unequal_keys:
        print 'param', 'dict1\t', 'dict2'
        for k in set(unequal_keys):
            print str(k)+'\t'+dict1.get(k, 'N\A')+'\t '+dict2.get(k, 'N\A')
    else:
        print 'Dicts are equal'

dict1 = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'}
dict2 = {1:'b', 2:'a', 3:'c', 4:'d', 6:'f'}

find_dict_diffs(dict1, dict2)

और परिणाम है:

param   dict1   dict2
1       a       b
2       b       a
5       e       N\A
6       N\A     f

1

जैसा कि अन्य उत्तरों में उल्लेख किया गया है, यूनीटेस्ट डिकट्स की तुलना करने के लिए कुछ अच्छा उत्पादन करता है, लेकिन इस उदाहरण में हम पहले एक संपूर्ण परीक्षण का निर्माण नहीं करना चाहते हैं।

बिना स्रोत के स्क्रैपिंग, ऐसा लगता है कि आप इसके साथ एक उचित समाधान प्राप्त कर सकते हैं:

import difflib
import pprint

def diff_dicts(a, b):
    if a == b:
        return ''
    return '\n'.join(
        difflib.ndiff(pprint.pformat(a, width=30).splitlines(),
                      pprint.pformat(b, width=30).splitlines())
    )

इसलिए

dictA = dict(zip(range(7), map(ord, 'python')))
dictB = {0: 112, 1: 'spam', 2: [1,2,3], 3: 104, 4: 111}
print diff_dicts(dictA, dictB)

का परिणाम:

{0: 112,
-  1: 121,
-  2: 116,
+  1: 'spam',
+  2: [1, 2, 3],
   3: 104,
-  4: 111,
?        ^

+  4: 111}
?        ^

-  5: 110}

कहाँ पे:

  • '-' पहले / दूसरे में नहीं बल्कि दूसरे तानाशाही में महत्वपूर्ण / मूल्यों को इंगित करता है
  • '+' दूसरे में कुंजी / मूल्यों को इंगित करता है, लेकिन पहले तानाशाह को नहीं

जैसे कि यूनिटेस्ट में, केवल एक चेतावनी यह है कि अंतिम मानचित्रण को अल्पविराम / ब्रैकेट के कारण एक अंतर माना जा सकता है।


1

@ मेक्सएक्स का एक उत्कृष्ट उत्तर है, unittestपायथन द्वारा प्रदान किए गए टूल का उपयोग करें :

import unittest


class Test(unittest.TestCase):
    def runTest(self):
        pass

    def testDict(self, d1, d2, maxDiff=None):
        self.maxDiff = maxDiff
        self.assertDictEqual(d1, d2)

फिर, आपके कोड में कहीं भी आप कॉल कर सकते हैं:

try:
    Test().testDict(dict1, dict2)
except Exception, e:
    print e

परिणामी आउटपुट से आउटपुट की तरह दिखता है diff, प्रत्येक पंक्ति के साथ शब्दकोशों को सुंदर रूप से मुद्रित करना +या -अलग करना।


0

यह सुनिश्चित नहीं है कि यह अभी भी प्रासंगिक है, लेकिन मुझे इस समस्या का सामना करना पड़ा है, मेरी स्थिति मुझे बस सभी नेस्टेड शब्दकोशों आदि के लिए परिवर्तनों के एक शब्दकोश को वापस करने की आवश्यकता है आदि वहां से एक अच्छा समाधान नहीं मिल सका, लेकिन मैंने एक साधारण फ़ंक्शन लिखना समाप्त कर दिया। यह करने के लिए । उम्मीद है की यह मदद करेगा,


2
यह सबसे कम मात्रा में कोड होगा जो ओपी की समस्या को वास्तव में एक लिंक के बजाय उत्तर में ठीक करता है। यदि लिंक मर जाता है या चलता है, तो आपका उत्तर बेकार हो जाता है।
जॉर्ज स्टॉकर

0

यदि आप मनमाने ढंग से तानाशाही संरचनाओं के साथ पूर्ण तुलना के लिए एक अंतर्निहित समाधान चाहते हैं, तो @ मैक्सक्स का उत्तर एक अच्छी शुरुआत है।

import unittest

test = unittest.TestCase()
test.assertEqual(dictA, dictB)

आप जाहिरा तौर पर उस तरह एक परीक्षण वर्ग को नहीं रोक सकते हैं, जो बहुत बुरा है।
बेन लियानैज

0

Ghostdog74 के उत्तर के आधार पर,

dicta = {"a":1,"d":2}
dictb = {"a":5,"d":2}

for value in dicta.values():
    if not value in dictb.values():
        print value

विभिन्नता के मूल्य को प्रिंट करेगा


0

डे चौराहे को खोजने के लिए यह कोशिश करें, दोनों की डिक्शनरी में जो चाबियां हैं, यदि आप चाहते हैं कि चाबी दूसरी डिक्शनरी पर न मिले, तो बस इसमें उपयोग न करें ...

intersect = filter(lambda x, dictB=dictB.keys(): x in dictB, dictA.keys())
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.