İki Python sözlüğünde bulunan anahtarlardaki farkı hesaplayın


171

İki Python sözlüğüm olduğunu varsayalım - dictAve dictB. İçinde mevcut olan dictBancak olmayan herhangi bir anahtar olup olmadığını öğrenmem gerekiyor dictA. Bu konuda en hızlı yol nedir?

Sözlük tuşlarını bir kümeye dönüştürmeli ve sonra devam etmeli miyim?

Düşüncelerinizi bilmekle ilgileniyor ...


Yanıtlarınız için teşekkürler.

Sorumu düzgün bir şekilde belirtmediğim için özür dilerim. Benim senaryom böyle - Ben dictAile aynı dictBolabilir veya bazı anahtarlar ile karşılaştırıldığında eksik olabilir dictBya da başka bazı anahtarların dictAdeğeri olan anahtarın değerine ayarlanması farklı olabilir .

Sorun, sözlüğün standart olmaması ve dikte edilebilecek değerlere sahip olabilmesidir.

Söyle

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

Bu yüzden 'key2' değeri yeni değere sıfırlanmalı ve 'key13' diktenin içine eklenmelidir. Anahtar değerinin sabit bir biçimi yok. Basit bir değer ya da bir dikte ya da bir dikte olabilir.

Yanıtlar:


234

Tuşlardaki ayar işlemlerini kullanabilirsiniz:

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

İşte tüm olasılıkları bulmak için bir sınıf: ne eklendi, ne kaldırıldı, hangi anahtar / değer çiftleri aynı ve hangi anahtar / değer çiftleri değiştirildi.

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

İşte bazı örnek çıktı:

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

Github repo olarak kullanılabilir: https://github.com/hughdbrown/dictdiffer


3
Akıllı çözüm, teşekkürler! Değişen veya değişmeyen değerlerin dikte örnekleri olup olmadığını kontrol ederek ve sınıfınızı kullanarak tekrar kontrol etmek için özyinelemeli bir işlevi çağırarak iç içe dicts ile çalışmasını sağladım.
AJJ

1
@AJJ Bu uygulamayı görmek isterim.
urschrei

1
Peki ya bir def update(self, new_dict): self.__init__(new_dict, self.current_dict)ya da benzeri bir haddeleme karşılaştırması yapabilirsiniz
Nick T

Bazı açıklamalar: DictDiffersınıf vatansız bir sınıftır ve bir işlev olabilir. changedVe unchangeddeğerler aynı döngüde hesaplanamıyor. Bu iki işlev , kesinlikle daha ucuz olan bir listyerine dönebilir set. Ayrıntılı karşılaştırma için Birim test çerçevesine göz atabilirsiniz : docs.python.org/2/library/unittest.html , assertDictEqualkaynak koddaki yöntemi takip etmeniz yeterlidir .
Laurent LAPORTE

1
FWIW, set(dictb)muhtemelen daha iyidir set(dictb.keys()).
mgilson

60

Farkı tekrar tekrar istiyorsanız, python için bir paket yazdım: https://github.com/seperman/deepdiff

Kurulum

PyPi'den yükle:

pip install deepdiff

Örnek kullanım

içe

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

Aynı nesne boş döner

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

Bir öğenin türü değişti

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

Bir öğenin değeri değişti

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

Öğe eklendi ve / veya kaldırıldı

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

Dize farkı

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

Dize farkı 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

Tür değişikliği

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

Liste farkı

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

Liste farkı 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}}}

Sıra veya yinelenenleri yok sayan liste farkı:

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

Sözlük içeren liste:

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

Setler:

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

İsimli Tuples:

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

Özel nesneler:

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

Nesne özelliği eklendi:

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

Bunun için teşekkür ederim! Sadece projeme uygulandı, harika çalışıyor!
gtalarico

1
@gtalarico Yardım etmekten mutluluk duyarız! Nazik sözler için teşekkürler!
Seperman

Liste sırası farkını göz ardı etme seçeneği var mı? çünkü uygulamam bunu umursamıyor.
Lei Yang

Güzel bir proje, tüm işleri benim tarafımdan asgari çabayla yaptı. Teşekkürler!
Stanislav Tsepa

@LeiYang Evet ayarlayabilirsiniz ignore_order=True. Dokümanları deepdiff.readthedocs.io/en/latest/diff.html
Seperman

18

"hızlı" olup olmadığından emin değilim, ama normalde bunu yapabilir

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

Değiştirmelisin dictave dictbo anahtarların içinde dictbolmadığını bilmek istediğinden dicta.
Gumbo

2
for key in dicta.keys():=>for key in dicta:
Jean-François Fabre

15

Alex Martelli'nin yazdığı gibi, B'deki herhangi bir anahtarın A'da olup olmadığını kontrol etmek istiyorsanız, any(True for k in dictB if k not in dictA)gitmek için bir yol olacaktır.

Eksik anahtarları bulmak için:

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

Yani bu iki çözüm hemen hemen aynı hızda.


8
Bu daha mantıklı:any(k not in dictA for k in dictB)
10'da hughdbrown

13

Gerçekten tam olarak ne demek istediğinizi kastediyorsanız (A'da değil, B'de "herhangi bir anahtar varsa" EĞER'i bulmanız gerekiyorsa, HANGİ TEKLER varsa bunlar değil), en hızlı yol:

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

Gerçekten HANGİ ANAHTARLARI, eğer varsa, B'de ve A'da değil, sadece "EĞER" değil, bu tür anahtarlar varsa bulmanız gerekiyorsa, mevcut cevaplar oldukça uygundur (ancak eğer gelecek sorularda daha fazla hassasiyet öneriyorum gerçekten ne demek istediğini ;-).



8

Hughdbrown'un en iyi yanıtı , kesinlikle en iyi yaklaşım olan set farkını kullanmanızı önerir:

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

Bu koddaki sorun, sadece iki set oluşturmak için iki liste oluşturmasıdır, bu nedenle 4N zaman ve 2N alan israfına neden olur. Ayrıca olması gerekenden biraz daha karmaşık.

Genellikle, bu büyük bir anlaşma değil, eğer öyleyse:

diff = dictb.keys() - dicta

Python 2

Python 2'de, keys()a değil, anahtarların listesini döndürür KeysView. Yani viewkeys()doğrudan sormak zorundasın .

diff = dictb.viewkeys() - dicta

Çift sürüm 2.7 / 3.x kodu için, umarım sixveya benzer bir şey kullanırsınız , böylece şunları kullanabilirsiniz six.viewkeys(dictb):

diff = six.viewkeys(dictb) - dicta

2.4-2.6'da, hayır KeysView. Ancak en azından 4N'den N'ye kadar olan maliyeti, ilk önce bir liste oluşturmak yerine, sol kümenizi doğrudan bir yineleyiciden oluşturarak azaltabilirsiniz:

diff = set(dictb) - dicta

Öğeler

Ben dictB ile aynı olabilir veya dictB ile karşılaştırıldığında bazı anahtarlar eksik olabilir bir dictA var veya başka bazı anahtarların değeri farklı olabilir

Yani anahtarları karşılaştırmanıza gerek yok, ama öğeleri. An ItemsViewyalnızca Setdeğerler dizgiler gibi yıkanabilirse. Eğer öyleyse, kolaydır:

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

Özyinelemeli fark

Soru doğrudan özyinelemeli bir fark istemese de, örnek değerlerin bazıları diktendir ve beklenen çıktının özyinelemeli olarak fark ettiği görülmektedir. Burada zaten bunun nasıl yapılacağını gösteren birden fazla cevap var.


2018 den kesin cevap
Jean-François Fabre

@ Jean-FrançoisFabre Tabii ki Python 2.4-2.6 olayları 2018'de zaten oldukça ilgisiz…
abarnert

bazı insanlar 2.6
Jean-François Fabre


3

İşte işe yarayan, değerlendiren anahtarlara izin veren Falseve mümkünse erken dökülmek için bir jeneratör ifadesi kullanan bir yol. Yine de son derece güzel değil.

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

DÜZENLE:

THC4k yorumuma başka bir cevap gönderdi. Yukarıdakileri yapmanın daha iyi ve güzel bir yolu:

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

Bunun aklımdan nasıl geçmediğinden emin değilim ...


bu daha önce Alex Martelli cevabı ile aynı cevaptır
Jean-François Fabre

Şimdi. Ne zaman (dokuz yıl önce, lol) gönderdi önceki cevap any(k for k in dictB if k not in dictA)(falsey tuşları için) aynı şey değildi. Düzenleme geçmişini / zaman damgalarını kontrol edin.
Steve Losh

3

Bu eski bir soru ve ihtiyacım olandan biraz daha az soruyor, bu yüzden bu cevap aslında bu sorunun sorduğundan daha fazlasını çözüyor. Bu sorudaki cevaplar aşağıdakileri çözmeme yardımcı oldu:

  1. (sordu) İki sözlük arasındaki farkları kaydedin
  2. # 1'deki farkları temel sözlüğe birleştir
  3. (sordu) İki sözlük arasındaki farkları birleştir (sözlük # 2'ye farklı bir sözlükmiş gibi davran)
  4. Eşya hareketlerini ve değişiklikleri tespit etmeye çalışın
  5. (sordu) Tüm bunları tekrar tekrar yap

Tüm bunlar JSON ile birlikte oldukça güçlü bir yapılandırma depolama desteği sağlar.

Çözüm ( ayrıca github üzerinde ):

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 ne olacak (TAM Nesneyi karşılaştırın)

PyDev-> yeni PyDev Modülü-> Modül: unittest

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

Büyük bir iç içe sözlüğünüz varsa ve içindeki her şeyi karşılaştırmak ve farklılıkları görmek istiyorsanız, bu harika. Teşekkürler!
Matthew Moisen

2

Python ≥ 2.7 üzerindeyse:

# 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

İşte 2 sözlük anahtarını derinlemesine karşılaştırmak için bir çözüm:

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

İşte ikiden fazla dikteyi karşılaştırabilen bir çözüm:

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

kullanım örneği:

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

1

İki sözlük arasındaki simetrik farkın tarifi:

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)

Ve sonuç:

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

1

Diğer cevaplarda belirtildiği gibi, unittest, zorlamaları karşılaştırmak için hoş bir çıktı üretir, ancak bu örnekte önce tüm bir test yapmak zorunda değiliz.

Unittest kaynağını kazıyarak, sadece bununla adil bir çözüm elde edebileceğiniz anlaşılıyor:

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

yani

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)

Sonuçlar:

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

+  4: 111}
?        ^

-  5: 110}

Nerede:

  • '-' birinci dikte anahtar / değerleri belirtir ancak ikinci dikte değil
  • '+' saniye içinde anahtar / değerleri belirtir, ancak ilk dikte değil

Unittest'te olduğu gibi, tek uyarı, son eşlemenin, sondaki virgül / braket nedeniyle bir fark olduğu düşünülebilmesidir.


1

@Maxx'un mükemmel bir cevabı var, unittestPython tarafından sağlanan araçları kullanın :

import unittest


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

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

Ardından, kodunuzdaki herhangi bir yeri arayabilirsiniz:

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

Sonuçta elde edilen çıktı diff, sözlüklerden farklı baskılar alarak +veya -bunlara farklı olan her satırı ekleyerek çıktıya benzer.


0

Hala ilgili olup olmadığını emin değilim ama bu sorunla karşılaştım, benim durumum ben sadece tüm iç içe sözlükler vb değişiklikleri için bir sözlük dönmek gerekiyordu. Orada iyi bir çözüm bulunamadı ama ben basit bir fonksiyon yazma sona erdi bunu yapmak için . Bu yardımcı olur umarım,


2
Bir bağlantı yerine OP'nin sorunun cevabını gerçekten düzelten en az miktarda koda sahip olmak tercih edilir. Bağlantı koparsa veya taşınırsa, cevabınız işe yaramaz hale gelir.
George Stocker

0

Keyifli diksiyon yapılarıyla tam bir karşılaştırma için yerleşik bir çözüm istiyorsanız, @ Maxx'in cevabı iyi bir başlangıçtır.

import unittest

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

Görünüşe göre çok kötü bir test sınıfı başlatamazsınız.
Ben Liyanage

0

Ghostdog74'ün cevabına dayanarak,

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

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

farklı dicta değeri yazdıracak


0

Sadece kullanın, de kesişim bulmak için ikinci Dictionarie bulunmayan anahtarları istiyorsanız, her iki Dictionarie olduğu anahtarları bu deneyin değil ...

intersect = filter(lambda x, dictB=dictB.keys(): x in dictB, dictA.keys())
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.