দুটি পাইথন অভিধানে থাকা কীগুলির মধ্যে পার্থক্য গণনা করুন


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
@ এজেজে আমি এই বাস্তবায়নটি দেখতে পছন্দ করব।
উর্ছ্রেই

1
কীভাবে def update(self, new_dict): self.__init__(new_dict, self.current_dict)বা এর মতো কীভাবে আপনি কোনও ঘূর্ণায়মান তুলনা করতে পারেন
নিক টিটি

কিছু মন্তব্য: DictDifferবর্গ একটি রাজ্যহীন শ্রেণি এবং একটি ফাংশন হতে পারে। changedএবং unchangedমান একই লুপ নির্ণিত যেতে পারে। এই দুটি ফাংশন একটি listপরিবর্তে ফিরে আসতে পারে setযা অবশ্যই কম ব্যয়বহুল। গভীর তুলনা করার জন্য, আপনি ইউনিট পরীক্ষার কাঠামোটি একবার দেখে নিতে পারেন: ডকস.পিথথন.আর / / লাইব্রেরি / ইউনাইটেস্ট এইচটিএমএল , assertDictEqualসোর্স কোডের পদ্ধতিটি অনুসরণ করুন ।
লরেন্ট LAPORTE

1
FWIW, set(dictb)সম্ভবত এর চেয়ে ভাল set(dictb.keys())
মিগিলসন

60

আপনি যদি পুনরাবৃত্তভাবে পার্থক্যটি চান তবে আমি অজগরটির জন্য একটি প্যাকেজ লিখেছি: https://github.com/seperman/DPdiff

স্থাপন

পিপিআই থেকে ইনস্টল করুন:

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

স্ট্রিং পার্থক্য 2

>>> 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। আপনি নথিগুলি ডিপডিড.ড্রেডহেডসকস.ওআইও
এনেস /

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:
জিন-ফ্রান্সোয়েস ফ্যাব্রে

15

অ্যালেক্স মার্টেলি যেমন লিখেছেন, আপনি যদি খালি কোন কী কী 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

আপনি যদি সত্যিই যা বলে থাকেন তা যদি আপনি বোঝাতে চান (তবে আপনাকে কেবল বিতে "কী আছে" এবং A তে নয়, তবে যদি সেগুলি হতে পারে তবে তাদের কোনওটিই খুঁজে পাওয়া উচিত), দ্রুততম উপায়টি হওয়া উচিত:

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

আপনার যদি সত্যিকারের কী কীগুলি সন্ধান করতে হয়, যদি থাকে তবে বি তে থাকে এবং এ তে নয় এবং কেবল "যদি" এই জাতীয় কীগুলি থাকে তবে বিদ্যমান উত্তরগুলি যথেষ্ট উপযুক্ত (তবে ভবিষ্যতের প্রশ্নগুলিতে আমি আরও নির্ভুলতার পরামর্শ দিই যদি তা হয় আসলে আপনি কি বলতে চাইছেন ;-)।



8

হিউডব্রাউন দ্বারা প্রাপ্ত শীর্ষ উত্তর সেট পার্থক্যটি ব্যবহার করার পরামর্শ দেয় যা অবশ্যই স্পষ্টতই সেরা পদ্ধতির:

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

এই কোডটির সাথে সমস্যাটি হ'ল এটি দুটি সেট তৈরি করতে দুটি তালিকা তৈরি করে, সুতরাং এটি 4N সময় এবং 2N স্থান নষ্ট করে। এটি হওয়া দরকারের চেয়ে কিছুটা জটিল।

সাধারণত, এটি কোনও বড় বিষয় নয়, তবে এটি যদি হয়:

diff = dictb.keys() - dicta

পাইথন 2

পাইথন 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 এ, নেই no KeysView । তবে আপনি প্রথমে একটি তালিকা তৈরির পরিবর্তে আপনার বাম সেটটি সরাসরি একটি পুনরুক্তিকারকের বাইরে তৈরি করে কমপক্ষে 4N থেকে N এ ব্যয়টি কাটাতে পারেন:

diff = set(dictb) - dicta

চলছে

আমার কাছে একটি ডোকা রয়েছে যা ডিকবির মতো হতে পারে বা ডিকবির তুলনায় কিছু কী হারিয়ে যেতে পারে অথবা কিছু কীগুলির মান আলাদা হতে পারে

সুতরাং আপনার কীগুলির সাথে তুলনা করার দরকার নেই, তবে আইটেমগুলি। মানগুলি স্ট্রিংয়ের মতো হ্যাশেবল হয় তবেই একটি ItemsViewহয় Set। যদি তারা হয় তবে এটি সহজ:

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

রিকার্সিভ ডিফ

যদিও প্রশ্নটি সরাসরি পুনরাবৃত্তির পার্থক্যের জন্য জিজ্ঞাসা করছে না, উদাহরণগুলির কয়েকটি মান হ'ল ডিক্টস এবং এটি প্রত্যাশিত আউটপুট পুনরাবৃত্তভাবে পৃথক করে ly এটি করার জন্য এখানে ইতিমধ্যে একাধিক উত্তর রয়েছে।


2018 থেকে নির্দিষ্ট উত্তর
জাঁ ফ্রাসোয়া Fabre

@ জিন-ফ্রেঞ্চোইস
ফ্যাব্রে


5

এই যুক্তি সম্পর্কে স্ট্যাকওভারফ্লোতে অন্য একটি প্রশ্ন রয়েছে এবং আমাকে স্বীকার করতে হবে যে এখানে একটি সহজ সমাধান ব্যাখ্যা করা হয়েছে: পাইথনের ডেটাডিফ লাইব্রেরি দুটি অভিধানের মধ্যে পার্থক্য মুদ্রণ করতে সহায়তা করে।


3

এখানে এমন একটি উপায় যা কাজ করবে, কীগুলি যা মূল্যায়ন করে তা মঞ্জুরি দেয় Falseএবং এখনও সম্ভব হলে জেনারেটর এক্সপ্রেশনটি খুব তাড়াতাড়ি পড়ে যায়। যদিও এটি খুব সুন্দর নয় pretty

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)

নিশ্চিত যে কীভাবে কখনই আমার মন কেটে গেল না ...


এটি পূর্বের অ্যালেক্স মার্তেলির উত্তরের মতো একই উত্তর
জিন-ফ্রানসোয়া ফ্যাব্রে

এটা এখন. আমি যখন এটি পোস্ট করেছি (নয় বছর আগে, 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

স্ট্যান্ডার্ড সম্পর্কে কী (সম্পূর্ণ বস্তুর তুলনা করুন)

পাইডেভ-> নতুন পাইডেভ মডিউল-> মডিউল: ইউনিটেস্ট

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

এটি যদি আপনার বিশাল নেস্টেড ডিকশনারি থাকে এবং আপনি ভিতরে প্রতিটি জিনিস তুলনা করতে এবং পার্থক্যগুলি দেখতে চান তবে এটি দুর্দান্ত। ধন্যবাদ!
ম্যাথু ময়েসেন

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

এখানে এমন একটি সমাধান রয়েছে যা দুটি ডিক্টের চেয়ে বেশি তুলনা করতে পারে:

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, অভিধানগুলিকে প্রিন্ট করে মুদ্রণ করে +বা -প্রতিটি লাইন পৃথক পৃথক prep


0

এটি এখনও প্রাসঙ্গিক কিনা তা নিশ্চিত নয় তবে আমি এই সমস্যাটি নিয়ে এসেছি, আমার পরিস্থিতি আমাকে কেবল সমস্ত নেস্টেড ডিকশনারি ইত্যাদির জন্য পরিবর্তনের একটি অভিধান ফেরত দেওয়ার দরকার ছিল। সেখানে খুব ভাল সমাধান খুঁজে পাওয়া যায়নি তবে আমি একটি সাধারণ ফাংশন লিখেছি এটি করতে । আশাকরি এটা সাহায্য করবে,


2
সংখ্যার কম সংখ্যক কোডের সাথে ওপির সমস্যাটি সংশোধন করে কোনও লিঙ্কের পরিবর্তে উত্তরে উত্তরে ঠিক করা বাঞ্ছনীয়। লিঙ্কটি যদি মারা যায় বা চলে যায় তবে আপনার উত্তরটি অকেজো হয়ে যায়।
জর্জ স্টকার

0

আপনি যদি স্বেচ্ছাচারী ডিক স্ট্রাকচারের সাথে সম্পূর্ণ তুলনা করার জন্য অন্তর্নির্মিত সমাধান চান তবে @ ম্যাক্সেক্সের উত্তরটি একটি ভাল শুরু।

import unittest

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

আপনি দৃশ্যত এর মতো পরীক্ষার ক্লাস ইনস্ট্যান্ট করতে পারবেন না, এটি খুব খারাপ।
বেন লিয়ানাজ

0

ঘোস্টডগ's৪ এর উত্তরের ভিত্তিতে,

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())
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.