Porównywanie dwóch słowników i sprawdzanie, ile par (klucz, wartość) jest równych


246

Mam dwa słowniki, ale dla uproszczenia wezmę te dwa:

>>> x = dict(a=1, b=2)
>>> y = dict(a=2, b=2)

Teraz chcę porównać, czy każda key, valuepara xma tę samą odpowiadającą wartość w y. Więc napisałem to:

>>> for x_values, y_values in zip(x.iteritems(), y.iteritems()):
        if x_values == y_values:
            print 'Ok', x_values, y_values
        else:
            print 'Not', x_values, y_values

I działa, ponieważ a tuplejest zwracane, a następnie porównywane pod kątem równości.

Moje pytania:

Czy to jest poprawne? Czy jest na to lepszy sposób? Lepiej nie w szybkości, mówię o elegancji kodu.

AKTUALIZACJA: Zapomniałem wspomnieć, że muszę sprawdzić, ile key, valuepar jest równych.


21
x == ypowinno być prawdziwe zgodnie z stackoverflow.com/a/5635309/186202
Natim

x == y powinno być prawdziwe. Można szybko sprawdzić w REPL. Proszę odnieść się: docs.python.org/2/library/stdtypes.html#mapping-types-dict
Vikrant

Odpowiedzi:


179

Jeśli chcesz wiedzieć, ile wartości pasuje do obu słowników, powinieneś to powiedzieć :)

Może coś takiego:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)

1
Ten sam błąd, jeśli istnieje element listy dla klucza dict. Myślę, że cmp jest lepszym sposobem na zrobienie tego, chyba że niczego mi brakuje.
Mutant

@ Mutant to inny problem. Przede wszystkim nie można utworzyć słownika z listkluczem. x = {[1,2]: 2}zawiedzie. Pytanie jest już ważne dicts.
AnnanFay,

@annan: źle, pytanie jest ogólne. przykład w opisie pytanie ma już „poprawnych dicts”. Jeśli opublikuję nowe pytanie o tym samym tytule, ale z innym „nieważnym” dyktando, ktoś oznaczy je jako duplikat. Downvoting.
ribamar,

6
@ribamar pytanie brzmi „Porównywanie dwóch słowników [...]”. „Nieprawidłowy dykt” z listkluczami nie jest prawidłowym kodem Pythona - klucze dykta muszą być niezmienne. Dlatego nie porównujesz słowników. Jeśli spróbujesz użyć listy jako klucza słownika, Twój kod nie zostanie uruchomiony. Nie masz obiektów do porównania. To tak, jakby pisać, x = dict(23\;dfg&^*$^%$^$%^)a następnie narzekać, że porównanie nie działa ze słownikiem. Oczywiście, że to nie zadziała. Z drugiej strony komentarz Tima dotyczy zmienności values, dlatego powiedziałem, że są to różne problemy.
AnnanFay,

1
@MikeyE - setwymaga, aby wartości były haszowalne, a dictklucze muszą być haszowalne. set(x.keys())zawsze będzie działać, ponieważ klucze muszą być haszowalne, ale set(x.values())zawiodą na wartościach, które nie są haszowalne.
Tim Tisdall

173

To, co chcesz zrobić, to po prostu x==y

To, co robisz, nie jest dobrym pomysłem, ponieważ elementy w słowniku nie powinny mieć żadnej kolejności. Możesz porównywać [('a',1),('b',1)]z [('b',1), ('a',1)](te same słowniki, inna kolejność).

Zobacz na przykład:

>>> x = dict(a=2, b=2,c=3, d=4)
>>> x
{'a': 2, 'c': 3, 'b': 2, 'd': 4}
>>> y = dict(b=2,c=3, d=4)
>>> y
{'c': 3, 'b': 2, 'd': 4}
>>> zip(x.iteritems(), y.iteritems())
[(('a', 2), ('c', 3)), (('c', 3), ('b', 2)), (('b', 2), ('d', 4))]

Różnica to tylko jeden element, ale Twój algorytm zobaczy, że wszystkie elementy są różne


@ THC4k, przepraszam, że nie wspomniałem. Ale muszę sprawdzić, ile wartości jest zgodnych w obu słownikach.
user225312,

Ok, więc w oparciu o moją aktualizację, czy mój sposób działania jest nadal nieprawidłowy?
user225312,

@AA: Dodałem, dlaczego twój nie działa, kiedy chcesz liczyć.
Jochen Ritzel

Rozumiem, ale w moim przypadku oba słowniki są tej samej długości. I zawsze tak będzie, ponieważ tak działa program.
user225312,

5
Począwszy od Pythona 3.6, dict jest zamawiany od razu po wyjęciu z pudełka.
Phil

163
def dict_compare(d1, d2):
    d1_keys = set(d1.keys())
    d2_keys = set(d2.keys())
    shared_keys = d1_keys.intersection(d2_keys)
    added = d1_keys - d2_keys
    removed = d2_keys - d1_keys
    modified = {o : (d1[o], d2[o]) for o in shared_keys if d1[o] != d2[o]}
    same = set(o for o in shared_keys if d1[o] == d2[o])
    return added, removed, modified, same

x = dict(a=1, b=2)
y = dict(a=2, b=2)
added, removed, modified, same = dict_compare(x, y)

7
Ten faktycznie obsługuje zmienne wartości w nagraniu!
Tim Tisdall

1
Po uruchomieniu tego nadal pojawia się błąd, gdy widzę, że mamy do czynienia ze zmiennymi wartościami: ValueError: Wartość prawdy DataFrame jest niejednoznaczna. Użyj a.empty, a.bool (), a.item (), a.any () lub a.all ().
Afflatus,

2
@Afflatus - DataFramez założenia nie pozwalają na prawdziwe porównania (chyba że ma długość 1), ponieważ dziedziczą numpy.ndarray. -kredyt na stackoverflow.com/a/33307396/994076
Daniel Myers

To absolutny klejnot.
pfabri

125

dic1 == dic2

Z dokumentacji Pythona :

W celu zilustrowania, następujące przykłady wszystkim zwrócić słownika równa się {"one": 1, "two": 2, "three": 3}:

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True

Podanie argumentów słów kluczowych, tak jak w pierwszym przykładzie, działa tylko w przypadku kluczy, które są prawidłowymi identyfikatorami języka Python. W przeciwnym razie można użyć dowolnego poprawnego klucza.

Obowiązuje zarówno dla, jak py2i dla py3.


3
Nie zgadzam się z @ ErkinAlpGüney. Czy możesz przedstawić dowód?
Qi Luo,

4
Nie zgadzam się z @ ErkinAlpGüney. Oficjalna dokumentacja pokazuje, że == rzeczywiście porównuje słowniki pod względem wartości, a nie adresu. docs.python.org/2/library/stdtypes.html#mapping-types-dict
Matthew Nakayama

3
Działa z Python 2.7.13
Jesuisme,

4
@ankostis:OrderedDict != dict
CONvid19

3
Czy możesz podać dane, które nie są prawdziwe?
CONvid19

55

Jestem nowy w Pythonie, ale skończyło się na zrobieniu czegoś podobnego do @mouad

unmatched_item = set(dict_1.items()) ^ set(dict_2.items())
len(unmatched_item) # should be 0

Operator XOR ( ^) powinien wyeliminować wszystkie elementy dict, gdy są one takie same w obu dictach.


28
Niestety nie działa to, jeśli wartości w dykcie są zmienne (tzn. Nie można ich mieszać). (Ex {'a':{'b':1}}daje TypeError: unhashable type: 'dict')
Tim Tisdall

54

Ponieważ wydaje się, że nikt o tym nie wspomniał deepdiff, dodam go tutaj dla kompletności. Uważam, że bardzo wygodne jest uzyskiwanie różnych (zagnieżdżonych) obiektów w ogóle:

Instalacja

pip install deepdiff

Przykładowy kod

import deepdiff
import json

dict_1 = {
    "a": 1,
    "nested": {
        "b": 1,
    }
}

dict_2 = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}

diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(diff, indent=4))

Wynik

{
    "values_changed": {
        "root['a']": {
            "new_value": 2,
            "old_value": 1
        },
        "root['nested']['b']": {
            "new_value": 2,
            "old_value": 1
        }
    }
}

Uwaga o ładnym wydrukowaniu wyniku do kontroli: powyższy kod działa, jeśli oba nagrania mają te same klucze atrybutów (z możliwie różnymi wartościami atrybutów jak w przykładzie). Jeśli jednak "extra"atrybut jest obecny, to jeden ze słowników, json.dumps()kończy się niepowodzeniem

TypeError: Object of type PrettyOrderedSet is not JSON serializable

Rozwiązanie: użyj diff.to_json()i json.loads()/ json.dumps()do ładnego wydruku:

import deepdiff
import json

dict_1 = {
    "a": 1,
    "nested": {
        "b": 1,
    },
    "extra": 3
}

dict_2 = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}

diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(json.loads(diff.to_json()), indent=4))  

Wynik:

{
    "dictionary_item_removed": [
        "root['extra']"
    ],
    "values_changed": {
        "root['a']": {
            "new_value": 2,
            "old_value": 1
        },
        "root['nested']['b']": {
            "new_value": 2,
            "old_value": 1
        }
    }
}

Alternatywnie: użyj pprint, powoduje inne formatowanie:

import pprint

# same code as above

pprint.pprint(diff, indent=4)

Wynik:

{   'dictionary_item_removed': [root['extra']],
    'values_changed': {   "root['a']": {   'new_value': 2,
                                           'old_value': 1},
                          "root['nested']['b']": {   'new_value': 2,
                                                     'old_value': 1}}}

2
Ciekawy. Dziękuję za odpowiedź. Przydatne dla mnie przynajmniej. Ta odpowiedź wymaga więcej głosów pozytywnych.
Archit Kapoor,

46

Po prostu użyj:

assert cmp(dict1, dict2) == 0

6
Wydaje się, że zadaniem jest nie tylko sprawdzenie, czy zawartość obu jest taka sama, ale także przedstawienie raportu o różnicach
Diego Tercero,

29
Uważam, że jest to identyczne zdict1 == dict2
Trey Hunner

10
Dla każdego, kto używa Python3.5, cmpwbudowane zostało usunięte (i powinno być traktowane jako usunięte wcześniej . Alternatywa, którą proponują: (a > b) - (a < b) == cmp(a, b)dla funkcjonalnego odpowiednika (lub lepszego __eq__i __hash__)
nerdwaller

3
@nerdwaller - dykt nie są typami uporządkowanymi, więc dict_a> dict_b podniósłby TypeError:unorderable types: dict() < dict()
Stefano

2
@Stefano: Dobra rozmowa, mój komentarz był bardziej do ogólnego porównania w pythonie (nie zwracałem uwagi na faktyczną odpowiedź, mój błąd).
nerdwaller

9

Odpowiedź @mouada jest dobra, jeśli założymy, że oba słowniki zawierają tylko proste wartości. Jeśli jednak masz słowniki zawierające słowniki, otrzymasz wyjątek, ponieważ słowniki nie podlegają haszowaniu.

Z czubka mojej głowy może działać coś takiego:

def compare_dictionaries(dict1, dict2):
     if dict1 is None or dict2 is None:
        print('Nones')
        return False

     if (not isinstance(dict1, dict)) or (not isinstance(dict2, dict)):
        print('Not dict')
        return False

     shared_keys = set(dict1.keys()) & set(dict2.keys())

     if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())):
        print('Not all keys are shared')
        return False


     dicts_are_equal = True
     for key in dict1.keys():
         if isinstance(dict1[key], dict) or isinstance(dict2[key], dict):
             dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key])
         else:
             dicts_are_equal = dicts_are_equal and all(atleast_1d(dict1[key] == dict2[key]))

     return dicts_are_equal

Jeśli użyjesz not isinstance(dict1, dict)zamiast type(dict1) is not dict, będzie to działać na innych klasach opartych na dict. Also, instead of (dict1 [klucz] == dict2 [klucz]) , you can do wszystkie (atleast_1d (dict1 [klucz] == dict2 [klucz])) `przynajmniej do obsługi tablic.
EL_DON

+1, ale możesz się wyrwać, for loopgdy tylko staniesz dicts_are_equalsię fałszywy. Nie trzeba kontynuować.
pfabri

6

Jeszcze inną możliwością, aż do ostatniej nuty OP, jest porównanie skrótów ( SHAlub MD) nagrań zrzuconych jako JSON. Sposób budowania skrótów gwarantuje, że jeśli są one równe, łańcuchy źródłowe są również równe. Jest to bardzo szybkie i matematyczne.

import json
import hashlib

def hash_dict(d):
    return hashlib.sha1(json.dumps(d, sort_keys=True)).hexdigest()

x = dict(a=1, b=2)
y = dict(a=2, b=2)
z = dict(a=1, b=2)

print(hash_dict(x) == hash_dict(y))
print(hash_dict(x) == hash_dict(z))

2
To całkowicie błędne, parsowanie danych do JSON jest naprawdę powolne. Zatem haszowanie tego ogromnego utworu, który właśnie stworzyłeś, jest jeszcze gorsze. Nigdy nie powinieneś tego robić
Bruno,

7
@Bruno: cytując OP: „Lepiej nie przyśpieszać, mówię o elegancji kodu”
WoJ

2
Nie jest wcale elegancki, wydaje się niebezpieczny i jest zbyt skomplikowany z powodu naprawdę prostego problemu
Bruno

7
@Bruno: elegancja jest subiektywna. Rozumiem, że ci się nie podoba (i prawdopodobnie przegłosował). To nie to samo co „źle”.
WoJ

4
To świetna odpowiedź. json.dumps(d, sort_keys=True)da ci kanoniczny JSON, dzięki czemu będziesz mieć pewność, że oba dyktanda są równoważne. To zależy również od tego, co próbujesz osiągnąć. Gdy tylko wartość nie będzie JSON możliwa do serializacji, zakończy się niepowodzeniem. Dla tych, którzy twierdzą, że jest nieefektywny, spójrz na projekt ujson.
Natim

6

Funkcja jest w porządku IMO, przejrzysta i intuicyjna. Ale żeby dać ci (inną) odpowiedź, oto moje przejście:

def compare_dict(dict1, dict2):
    for x1 in dict1.keys():
        z = dict1.get(x1) == dict2.get(x1)
        if not z:
            print('key', x1)
            print('value A', dict1.get(x1), '\nvalue B', dict2.get(x1))
            print('-----\n')

Może być przydatny dla ciebie lub kogokolwiek innego ...

EDYTOWAĆ:

Stworzyłem rekurencyjną wersję powyższej. Nie widziałem tego w innych odpowiedziach

def compare_dict(a, b):
    # Compared two dictionaries..
    # Posts things that are not equal..
    res_compare = []
    for k in set(list(a.keys()) + list(b.keys())):
        if isinstance(a[k], dict):
            z0 = compare_dict(a[k], b[k])
        else:
            z0 = a[k] == b[k]

        z0_bool = np.all(z0)
        res_compare.append(z0_bool)
        if not z0_bool:
            print(k, a[k], b[k])
    return np.all(res_compare)

2
Poprawmy to, aby działało w obie strony. Wiersz 2: „dla x1 w zestawie (dict1.keys ()). Union (dict2.keys ()):”
nkadwa

Dzięki @nkadwa, robi to teraz
zwep

5

Aby sprawdzić, czy dwa dykty są takie same w kluczach i wartościach:

def dicts_equal(d1,d2):
    """ return True if all keys and values are the same """
    return all(k in d2 and d1[k] == d2[k]
               for k in d1) \
        and all(k in d1 and d1[k] == d2[k]
               for k in d2)

Jeśli chcesz zwrócić różne wartości, napisz je inaczej:

def dict1_minus_d2(d1, d2):
    """ return the subset of d1 where the keys don't exist in d2 or
        the values in d2 are different, as a dict """
    return {k,v for k,v in d1.items() if k in d2 and v == d2[k]}

Trzeba by to nazwać dwa razy, tj

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))

3

Kod

def equal(a, b):
    type_a = type(a)
    type_b = type(b)
    
    if type_a != type_b:
        return False
    
    if isinstance(a, dict):
        if len(a) != len(b):
            return False
        for key in a:
            if key not in b:
                return False
            if not equal(a[key], b[key]):
                return False
        return True

    elif isinstance(a, list):
        if len(a) != len(b):
            return False
        while len(a):
            x = a.pop()
            index = indexof(x, b)
            if index == -1:
                return False
            del b[index]
        return True
        
    else:
        return a == b

def indexof(x, a):
    for i in range(len(a)):
        if equal(x, a[i]):
            return i
    return -1

Test

>>> a = {
    'number': 1,
    'list': ['one', 'two']
}
>>> b = {
    'list': ['two', 'one'],
    'number': 1
}
>>> equal(a, b)
True

3

Proste porównanie z == powinno wystarczyć w dzisiejszych czasach (python 3.8). Nawet jeśli porównasz te same dykty w innej kolejności (ostatni przykład). Najlepsze jest to, że do tego nie potrzebujesz pakietu innej firmy.

a = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
b = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

c = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
d = {'one': 'dog', 'two': 'cat', 'three': 'mouse', 'four': 'fish'}

e = {'one': 'cat', 'two': 'dog', 'three': 'mouse'}
f = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

g = {'two': 'cat', 'one': 'dog', 'three': 'mouse'}
h = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}


print(a == b) # True
print(c == d) # False
print(e == f) # False
print(g == h) # True

2

Spóźnienie w mojej odpowiedzi jest lepsze niż nigdy!

Porównaj Not_Equal jest bardziej wydajne niż porównywanie Equal. W związku z tym dwa dyktaty nie są sobie równe, jeśli w kluczu nie znaleziono żadnych kluczowych wartości w jednym dykcie. Poniższy kod bierze pod uwagę, że być może porównujesz domyślny słownik i dlatego używa get zamiast getitem [].

Użycie pewnego rodzaju wartości losowej jako domyślnej w wywołaniu get równej pobieranemu kluczowi - na wypadek, gdyby dyktony miały wartość None jako wartość w jednym dycie, a ten klucz nie istnieje w drugim. Również warunek get! = Jest sprawdzany przed nieuwzględnieniem wydajności, ponieważ sprawdzane są klucze i wartości z obu stron jednocześnie.

def Dicts_Not_Equal(first,second):
    """ return True if both do not have same length or if any keys and values are not the same """
    if len(first) == len(second): 
        for k in first:
            if first.get(k) != second.get(k,k) or k not in second: return (True)
        for k in second:         
            if first.get(k,k) != second.get(k) or k not in first: return (True)
        return (False)   
    return (True)

2

Korzystam z tego rozwiązania, które działa idealnie dla mnie w Python 3


import logging
log = logging.getLogger(__name__)

...

    def deep_compare(self,left, right, level=0):
        if type(left) != type(right):
            log.info("Exit 1 - Different types")
            return False

        elif type(left) is dict:
            # Dict comparison
            for key in left:
                if key not in right:
                    log.info("Exit 2 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[str(key)], right[str(key)], level +1 ):
                        log.info("Exit 3 - different children")
                        return False
            return True
        elif type(left) is list:
            # List comparison
            for key in left:
                if key not in right:
                    log.info("Exit 4 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[left.index(key)], right[right.index(key)], level +1 ):
                        log.info("Exit 5 - different children")
                        return False
            return True
        else:
            # Other comparison
            return left == right

        return False

Porównuje dict, list i wszelkie inne typy, które same implementują operatora „==”. Jeśli chcesz porównać coś innego, musisz dodać nową gałąź w „drzewie drzewa”.

Mam nadzieję, że to pomaga.


2

dla python3:

data_set_a = dict_a.items()
data_set_b = dict_b.items()

difference_set = data_set_a ^ data_set_b

1
>>> hash_1
{'a': 'foo', 'b': 'bar'}
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_1 = set (hash_1.iteritems())
>>> set_1
set([('a', 'foo'), ('b', 'bar')])
>>> set_2 = set (hash_2.iteritems())
>>> set_2
set([('a', 'foo'), ('b', 'bar')])
>>> len (set_1.difference(set_2))
0
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...    print "The two hashes match."
...
The two hashes match.
>>> hash_2['c'] = 'baz'
>>> hash_2
{'a': 'foo', 'c': 'baz', 'b': 'bar'}
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
>>>
>>> hash_2.pop('c')
'baz'

Oto kolejna opcja:

>>> id(hash_1)
140640738806240
>>> id(hash_2)
140640738994848

Jak widać, dwa identyfikatory są różne. Ale operatory porównywania bogatego wydają się załatwić sprawę:

>>> hash_1 == hash_2
True
>>>
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_2 = set (hash_2.iteritems())
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
The two hashes match.
>>>

1

W PyUnit istnieje metoda, która pięknie porównuje słowniki. Przetestowałem go za pomocą następujących dwóch słowników i robi dokładnie to, czego szukasz.

d1 = {1: "value1",
      2: [{"subKey1":"subValue1",
           "subKey2":"subValue2"}]}
d2 = {1: "value1",
      2: [{"subKey2":"subValue2",
           "subKey1": "subValue1"}]
      }


def assertDictEqual(self, d1, d2, msg=None):
        self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
        self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')

        if d1 != d2:
            standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
            diff = ('\n' + '\n'.join(difflib.ndiff(
                           pprint.pformat(d1).splitlines(),
                           pprint.pformat(d2).splitlines())))
            standardMsg = self._truncateMessage(standardMsg, diff)
            self.fail(self._formatMessage(msg, standardMsg))

Nie polecam importowania unittestdo kodu produkcyjnego. Moja myśl jest taka, że ​​źródło PyUnit może zostać ponownie opracowane tak, aby działało w produkcji. Wykorzystuje, pprintktóre „ładne” drukuje słowniki. Łatwo jest dostosować ten kod, aby był „gotowy do produkcji”.


1

zobacz obiekty widok słownika: https://docs.python.org/2/library/stdtypes.html#dict

W ten sposób możesz odjąć dictView2 od dictView1, a to zwróci zestaw par klucz / wartość, które są różne w dictView2:

original = {'one':1,'two':2,'ACTION':'ADD'}
originalView=original.viewitems()
updatedDict = {'one':1,'two':2,'ACTION':'REPLACE'}
updatedDictView=updatedDict.viewitems()
delta=original | updatedDict
print delta
>>set([('ACTION', 'REPLACE')])

Możesz przecinać, łączyć, różnicę (pokazaną powyżej), różnicę symetryczną tych obiektów widoku słownika.
Lepszy? Szybciej? - nie jestem pewien, ale stanowi część standardowej biblioteki - co czyni go dużym plusem pod względem przenośności


1

Poniższy kod pomoże ci porównać listę dykt w Pythonie

def compate_generic_types(object1, object2):
    if isinstance(object1, str) and isinstance(object2, str):
        return object1 == object2
    elif isinstance(object1, unicode) and isinstance(object2, unicode):
        return object1 == object2
    elif isinstance(object1, bool) and isinstance(object2, bool):
        return object1 == object2
    elif isinstance(object1, int) and isinstance(object2, int):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, float):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, int):
        return object1 == float(object2)
    elif isinstance(object1, int) and isinstance(object2, float):
        return float(object1) == object2

    return True

def deep_list_compare(object1, object2):
    retval = True
    count = len(object1)
    object1 = sorted(object1)
    object2 = sorted(object2)
    for x in range(count):
        if isinstance(object1[x], dict) and isinstance(object2[x], dict):
            retval = deep_dict_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        elif isinstance(object1[x], list) and isinstance(object2[x], list):
            retval = deep_list_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        else:
            retval = compate_generic_types(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False

    return retval

def deep_dict_compare(object1, object2):
    retval = True

    if len(object1) != len(object2):
        return False

    for k in object1.iterkeys():
        obj1 = object1[k]
        obj2 = object2[k]
        if isinstance(obj1, list) and isinstance(obj2, list):
            retval = deep_list_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

        elif isinstance(obj1, dict) and isinstance(obj2, dict):
            retval = deep_dict_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False
        else:
            retval = compate_generic_types(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

    return retval

3
Witamy w Stack Overflow! Ten fragment kodu może rozwiązać pytanie, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie dla czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu. Staraj się również nie tłoczyć kodu objaśniającymi komentarzami, co zmniejsza czytelność zarówno kodu, jak i objaśnień!
Filnor

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

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

METHOD 1:

>>> common_item = x.items()&y.items() #using union,x.item() 
>>> common_item
{('c', 3)}

METHOD 2:

 >>> for i in x.items():
        if i in y.items():
           print('true')
        else:
           print('false')


false
false
true

0

W Pythonie 3.6 można to zrobić jako:

if (len(dict_1)==len(dict_2): 
  for i in dict_1.items():
        ret=bool(i in dict_2.items())

zmienna ret będzie prawdziwa, jeśli wszystkie elementy dict_1 obecne w dict_2


0

Oto moja odpowiedź: użyj rekursywnego sposobu:

def dict_equals(da, db):
    if not isinstance(da, dict) or not isinstance(db, dict):
        return False
    if len(da) != len(db):
        return False
    for da_key in da:
        if da_key not in db:
            return False
        if not isinstance(db[da_key], type(da[da_key])):
            return False
        if isinstance(da[da_key], dict):
            res = dict_equals(da[da_key], db[da_key])
            if res is False:
                return False
        elif da[da_key] != db[da_key]:
            return False
    return True

a = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
b = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
print dict_equals(a, b)

Mam nadzieję, że to pomaga!


0

Dlaczego nie po prostu iterować po jednym słowniku i sprawdzać drugi w trakcie procesu (zakładając, że oba słowniki mają te same klucze)?

x = dict(a=1, b=2)
y = dict(a=2, b=2)

for key, val in x.items():
    if val == y[key]:
        print ('Ok', val, y[key])
    else:
        print ('Not', val, y[key])

Wynik:

Not 1 2
Ok 2 2

0

Najłatwiejszym (i jednym z bardziej niezawodnych) do wykonania głębokiego porównania dwóch słowników jest ich serializacja w formacie JSON, sortowanie kluczy i porównanie wyników łańcucha:

import json
if json.dumps(x, sort_keys=True) == json.dumps(y, sort_keys=True):
   ... Do something ...

-7
import json

if json.dumps(dict1) == json.dumps(dict2):
    print("Equal")

1
Może to nie zrobić dokładnie tego, o co dokładnie poprosono i pobiera bibliotekę json std lib, ale działa (co json.dumpsjest deterministyczne przy ustawieniach domyślnych).
Daniel Farrell,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.