Vergleichen von zwei Wörterbüchern und Überprüfen, wie viele (Schlüssel-, Wert-) Paare gleich sind

245

Ich habe zwei Wörterbücher, aber zur Vereinfachung nehme ich diese beiden:

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

Nun möchte ich vergleichen, ob jedes key, valuePaar in xden gleichen entsprechenden Wert in hat y. Also habe ich folgendes geschrieben:

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

Und es funktioniert, da a tuplezurückgegeben und dann auf Gleichheit verglichen wird.

Meine Fragen:

Ist das richtig? Gibt es einen besseren Weg, dies zu tun? Besser nicht in der Geschwindigkeit, ich spreche von Code-Eleganz.

UPDATE: Ich habe vergessen zu erwähnen, dass ich überprüfen muss, wie viele key, valuePaare gleich sind.

user225312
quelle
21
x == ysollte laut stackoverflow.com/a/5635309/186202
Natim
x == y sollte wahr sein. Man kann REPL schnell einchecken. Bitte beziehen Sie sich auf: docs.python.org/2/library/stdtypes.html#mapping-types-dict
Vikrant

Antworten:

179

Wenn Sie wissen möchten, wie viele Werte in beiden Wörterbüchern übereinstimmen, sollten Sie das gesagt haben :)

Vielleicht so etwas:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)
Mouad
quelle
1
Gleicher Fehler, wenn für den Diktatschlüssel ein Listenelement vorhanden ist. Ich denke, cmp ist der bessere Weg, es sei denn, ich vermisse etwas.
Mutant
@ Mutant das ist ein anderes Problem. Sie können überhaupt kein Wörterbuch mit einem listSchlüssel erstellen . x = {[1,2]: 2}wird versagen. Die Frage hat bereits Gültigkeit dicts.
AnnanFay
@annan: falsch, die frage ist generisch. Das Beispiel in der Fragenbeschreibung hat bereits "gültige Diktate". Wenn ich eine neue Frage mit demselben Titel, aber einem anderen "ungültigen" Diktat poste, wird sie von jemandem als doppelt markiert. Downvoting.
Ribamar
6
@ribamar die Frage ist "Vergleichen von zwei Wörterbüchern [...]". Die ‚ungültig dict‘ oben mit listSchlüssel ist nicht gültig Python - Code - dict Schlüssel muss unveränderlich sein. Daher vergleichen Sie keine Wörterbücher. Wenn Sie versuchen, eine Liste als Wörterbuchschlüssel zu verwenden, wird Ihr Code nicht ausgeführt. Sie haben keine Objekte zum Vergleichen. Dies ist so, als würde man tippen und sich x = dict(23\;dfg&^*$^%$^$%^)dann beschweren, dass der Vergleich mit dem Wörterbuch nicht funktioniert. Natürlich wird es nicht funktionieren. Tims Kommentar ist dagegen veränderlich values, weshalb ich sagte, dass dies verschiedene Themen sind.
AnnanFay
1
@MikeyE - seterfordert, dass Werte hashbar sind und dictdass Schlüssel hashbar sind. set(x.keys())funktioniert immer, da Schlüssel hashbar sein müssen, aber set(x.values())bei Werten, die nicht hashbar sind, fehlschlagen.
Tim Tisdall
173

Was Sie tun möchten, ist einfach x==y

Was Sie tun, ist keine gute Idee, da die Elemente in einem Wörterbuch keine Reihenfolge haben sollen. Möglicherweise vergleichen Sie [('a',1),('b',1)]mit [('b',1), ('a',1)](gleiche Wörterbücher, unterschiedliche Reihenfolge).

Siehe zum Beispiel Folgendes:

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

Der Unterschied ist nur ein Element, aber Ihr Algorithmus wird feststellen, dass alle Elemente unterschiedlich sind

Jochen Ritzel
quelle
@ THC4k, sorry für nicht erwähnt. Aber ich muss überprüfen, wie viele Werte in beiden Wörterbüchern übereinstimmen.
user225312
Ok, ist meine Vorgehensweise aufgrund meines Updates immer noch falsch?
user225312
@AA: Ich habe hinzugefügt, warum deine nicht funktioniert, wenn du zählen willst.
Jochen Ritzel
Ich verstehe, aber in meinem Fall sind beide Wörterbücher gleich lang. Und das wird immer so sein, denn so funktioniert das Programm.
user225312
5
Ab Python 3.6 ist dict sofort einsatzbereit.
Phil
162
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)
Daniel Myers
quelle
7
Dieser behandelt tatsächlich veränderbare Werte im Diktat!
Tim Tisdall
1
Wenn ich dies ausführe, wird immer noch ein Fehler beim Umgang mit den veränderlichen Werten angezeigt: ValueError: Der Wahrheitswert eines DataFrame ist nicht eindeutig. Verwenden Sie a.empty, a.bool (), a.item (), a.any () oder a.all ().
Afflatus
2
@Afflatus - DataFrames erlauben von Natur aus keine wahrheitsgemäßen Vergleiche (es sei denn, sie haben eine Länge von 1), von denen sie erben numpy.ndarray. -credit to stackoverflow.com/a/33307396/994076
Daniel Myers
Dies ist ein absolutes Juwel.
Pfabri
125

dic1 == dic2

Aus Python-Dokumenten :

Zur Veranschaulichung, kehren die folgenden Beispiele alle ein Wörterbuch gleich zu {"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

Das Bereitstellen von Schlüsselwortargumenten wie im ersten Beispiel funktioniert nur für Schlüssel, die gültige Python-Bezeichner sind. Andernfalls können beliebige gültige Schlüssel verwendet werden.

Gültig für py2und py3.

CONvid19
quelle
3
Ich stimme @ ErkinAlpGüney nicht zu. Könnten Sie einen Beweis erbringen?
Qi Luo
4
Ich bin nicht einverstanden mit @ ErkinAlpGüney. Die offizielle Dokumentation zeigt, dass == Wörterbücher tatsächlich nach Wert und nicht nach Adresse vergleicht. docs.python.org/2/library/stdtypes.html#mapping-types-dict
Matthew Nakayama
3
Funktioniert für Python 2.7.13
Jesuisme
4
@ankostis:OrderedDict != dict
CONvid19
3
Können Sie bitte eine Eingabe machen, bei der dies nicht der Fall ist?
CONvid19
55

Ich bin neu in Python, aber am Ende habe ich etwas Ähnliches wie @mouad gemacht

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

Der XOR-Operator ( ^) sollte alle Elemente des Diktats entfernen, wenn sie in beiden Diktaten gleich sind.

philipp
quelle
28
Leider funktioniert dies nicht, wenn die Werte im Diktat veränderbar sind (dh nicht hashbar). (Ex {'a':{'b':1}}gibt TypeError: unhashable type: 'dict')
Tim Tisdall
54

Da anscheinend niemand erwähnt hat deepdiff, werde ich es der Vollständigkeit halber hier hinzufügen. Ich finde es sehr praktisch, Diff von (verschachtelten) Objekten im Allgemeinen zu erhalten:

Installation

pip install deepdiff

Beispielcode

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

Ausgabe

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

Hinweis zum hübschen Drucken des Ergebnisses zur Überprüfung: Der obige Code funktioniert, wenn beide Dikte dieselben Attributschlüssel haben (mit möglicherweise unterschiedlichen Attributwerten wie im Beispiel). Wenn jedoch ein "extra"Attribut vorhanden ist, ist eines der Diktate, json.dumps()schlägt mit fehl

TypeError: Object of type PrettyOrderedSet is not JSON serializable

Lösung: Verwenden diff.to_json()und json.loads()/ oder json.dumps()hübsch drucken:

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

Ausgabe:

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

Alternative: Verwendung pprintführt zu einer anderen Formatierung:

import pprint

# same code as above

pprint.pprint(diff, indent=4)

Ausgabe:

{   'dictionary_item_removed': [root['extra']],
    'values_changed': {   "root['a']": {   'new_value': 2,
                                           'old_value': 1},
                          "root['nested']['b']": {   'new_value': 2,
                                                     'old_value': 1}}}
Sumudu
quelle
2
Interessant. Vielen Dank für die Beantwortung. Nützlich für mich zumindest. Diese Antwort braucht mehr Upvotes.
Archit Kapoor
46

Benutz einfach:

assert cmp(dict1, dict2) == 0
Shiyu
quelle
6
Es scheint, dass die Aufgabe nicht nur darin besteht, zu überprüfen, ob der Inhalt von beiden gleich ist, sondern auch einen Bericht über die Unterschiede zu geben
Diego Tercero
29
Ich glaube, das ist identisch mitdict1 == dict2
Trey Hunner
10
Für alle, die Python3.5 verwenden, wurde das cmpintegrierte Element entfernt (und sollte wie zuvor behandelt behandelt werden . Eine Alternative, die sie vorschlagen: (a > b) - (a < b) == cmp(a, b)für ein funktionales Äquivalent (oder besser __eq__und __hash__)
Nerdwaller
3
@nerdwaller - dicts sind keine bestellbaren Typen, also würde dict_a> dict_b ein TypeError:unorderable types: dict() < dict()
Stefano
2
@Stefano: Guter Anruf, mein Kommentar war eher zum allgemeinen Vergleich in Python gedacht (ich habe nicht auf die eigentliche Antwort geachtet, mein Fehler).
Nerdwaller
9

Die Antwort von @mouad ist nett, wenn Sie davon ausgehen, dass beide Wörterbücher nur einfache Werte enthalten. Wenn Sie jedoch Wörterbücher haben, die Wörterbücher enthalten, erhalten Sie eine Ausnahme, da Wörterbücher nicht hashbar sind.

Auf den ersten Blick könnte so etwas funktionieren:

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
Alexander
quelle
Wenn Sie not isinstance(dict1, dict)stattdessen verwenden type(dict1) is not dict, funktioniert dies für andere Klassen, die auf dict. Also, instead of (dict1 [Schlüssel] == dict2 [Schlüssel]) , you can do all (atleast_1d (dict1 [Schlüssel] == dict2 [Schlüssel])) `basieren, um mindestens Arrays zu verarbeiten.
EL_DON
+1, aber du könntest aus deinem ausbrechen, for loopsobald dein dicts_are_equalfalsch wird. Es besteht keine Notwendigkeit, weiterzumachen.
Pfabri
6

Eine weitere Möglichkeit, bis zur letzten Anmerkung des OP, besteht darin, die Hashes ( SHAoder MD) der als JSON abgelegten Dikte zu vergleichen . Die Art und Weise, wie Hashes erstellt werden, garantiert, dass auch die Quellzeichenfolgen gleich sind, wenn sie gleich sind. Dies ist sehr schnell und mathematisch einwandfrei.

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))
WoJ
quelle
2
Das ist völlig falsch, nur das Parsen der Daten in json ist sehr langsam. Dann ist es noch schlimmer, den riesigen Ring zu hacken, den Sie gerade erstellt haben. Sie sollten das niemals tun
Bruno
7
@ Bruno: Zitat des OP: "Besser nicht in der Geschwindigkeit, ich spreche über Code Eleganz"
WoJ
2
Es ist überhaupt nicht elegant, es fühlt sich unsicher an und es ist zu kompliziert für ein wirklich einfaches Problem
Bruno
7
@ Bruno: Eleganz ist subjektiv. Ich kann verstehen, dass Sie es nicht mögen (und wahrscheinlich herabgestimmt haben). Dies ist nicht dasselbe wie "falsch".
WoJ
4
Dies ist eine großartige Antwort. json.dumps(d, sort_keys=True)Sie erhalten kanonisches JSON, sodass Sie sicher sein können, dass beide Diktate gleichwertig sind. Es kommt auch darauf an, was Sie erreichen wollen. Sobald der Wert nicht JSON-serialisierbar ist, schlägt er fehl. Wer also sagt, dass es ineffizient ist, sollte sich das ujson-Projekt ansehen.
Natim
6

Die Funktion ist gut IMO, klar und intuitiv. Aber nur um Ihnen (eine andere) Antwort zu geben, hier ist mein Los:

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

Kann für Sie oder für andere nützlich sein.

BEARBEITEN:

Ich habe eine rekursive Version der obigen erstellt. Habe das in den anderen Antworten nicht gesehen

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)
zwep
quelle
2
Lassen Sie es uns verbessern, damit es in beide Richtungen funktioniert. Zeile 2: "für x1 in set (dict1.keys ()). Union (dict2.keys ()):"
nkadwa
Danke @nkadwa, das tut es jetzt
zwep
5

So testen Sie, ob zwei Diktate in Schlüsseln und Werten gleich sind:

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)

Wenn Sie die unterschiedlichen Werte zurückgeben möchten, schreiben Sie sie anders:

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

Sie müssten es zweimal nennen, dh

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))
Simonltwick
quelle
3

Code

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

Prüfung

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

Ein einfacher Vergleich mit == sollte heutzutage ausreichen (Python 3.8). Auch wenn Sie dieselben Diktate in einer anderen Reihenfolge vergleichen (letztes Beispiel). Das Beste ist, Sie benötigen kein Paket von Drittanbietern, um dies zu erreichen.

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
Verneblig
quelle
2

Zu spät in meiner Antwort zu sein ist besser als nie!

Not_Equal vergleichen ist effizienter als Equal vergleichen. Daher sind zwei Diktate nicht gleich, wenn im anderen Diktat keine Schlüsselwerte in einem Diktat gefunden werden. Der folgende Code berücksichtigt, dass Sie möglicherweise das Standarddiktat vergleichen und daher get anstelle von getitem [] verwenden.

Verwenden Sie im get-Aufruf standardmäßig eine Art Zufallswert, der dem abzurufenden Schlüssel entspricht - nur für den Fall, dass das Diktat in einem Diktat den Wert None als Wert hat und dieser Schlüssel im anderen nicht vorhanden ist. Außerdem wird die get! = -Zustand vor der Nicht-In-Bedingung auf Effizienz geprüft, da Sie die Schlüssel und Werte von beiden Seiten gleichzeitig prüfen.

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)
Benutzer-Asterix
quelle
2

Ich verwende diese Lösung, die in Python 3 perfekt für mich funktioniert


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

Es vergleicht Diktat, Liste und alle anderen Typen, die den Operator "==" selbst implementieren. Wenn Sie etwas anderes vergleichen müssen, müssen Sie einen neuen Zweig im "if-Baum" hinzufügen.

Hoffentlich hilft das.

Giovanni Basolu
quelle
2

für python3:

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

difference_set = data_set_a ^ data_set_b
Bryant
quelle
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'

Hier ist eine weitere Option:

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

Wie Sie sehen, sind die beiden IDs unterschiedlich. Aber die reichen Vergleichsoperatoren scheinen den Trick zu tun:

>>> 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.
>>>
Led Zeppelin
quelle
1

In PyUnit gibt es eine Methode, mit der Wörterbücher wunderbar verglichen werden können. Ich habe es mit den folgenden zwei Wörterbüchern getestet und es macht genau das, wonach Sie suchen.

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

Ich empfehle nicht, unittestin Ihren Produktionscode zu importieren . Meiner Meinung nach könnte die Quelle in PyUnit für die Produktion umgerüstet werden. Es verwendet, pprintwelche "hübschen Drucke" die Wörterbücher. Es scheint ziemlich einfach zu sein, diesen Code so anzupassen, dass er "produktionsbereit" ist.

MikeyE
quelle
1

Siehe Objekte der Wörterbuchansicht: https://docs.python.org/2/library/stdtypes.html#dict

Auf diese Weise können Sie dictView2 von dictView1 subtrahieren und es wird eine Reihe von Schlüssel / Wert-Paaren zurückgegeben, die sich in dictView2 unterscheiden:

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

Sie können diese Wörterbuchansichtsobjekte schneiden, vereinen, unterscheiden (siehe oben) und symmetrisch unterscheiden.
Besser? Schneller? - nicht sicher, aber Teil der Standardbibliothek - was es zu einem großen Plus für die Portabilität macht

tranimatronic
quelle
1

Der folgende Code hilft Ihnen, die Liste der Diktate in Python zu vergleichen

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
Vitthal Kadam
quelle
3
Willkommen bei Stack Overflow! Während dieses Code-Snippet die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen. Bitte versuchen Sie auch, Ihren Code nicht mit erklärenden Kommentaren zu überfüllen. Dies verringert die Lesbarkeit sowohl des Codes als auch der Erklärungen!
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
vidiv
quelle
0

In Python 3.6 kann dies wie folgt erfolgen:

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

Die Variable ret ist wahr, wenn alle Elemente von dict_1 in dict_2 vorhanden sind

Souravi Sinha
quelle
0

Hier ist meine Antwort: Verwenden Sie eine rekursive Methode:

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)

Hoffentlich hilft das!

William Xu
quelle
0

Warum nicht einfach ein Wörterbuch durchlaufen und dabei das andere überprüfen (vorausgesetzt, beide Wörterbücher haben die gleichen Schlüssel)?

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

Ausgabe:

Not 1 2
Ok 2 2
LevB
quelle
-7
import json

if json.dumps(dict1) == json.dumps(dict2):
    print("Equal")
Mariusz K.
quelle
1
Dies führt möglicherweise nicht zu dem, was genau angefordert wurde, und ruft die json std lib auf, funktioniert jedoch (wie json.dumpsbei den Standardeinstellungen deterministisch).
Daniel Farrell