Порівнюючи два словники та перевіряючи, скільки пар (ключ, значення) рівні


246

У мене є два словники, але для спрощення я візьму ці два:

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

Тепер я хочу порівняти, чи має кожна key, valueпара в xоднаковому значенні в y. Тому я написав це:

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

І він працює, оскільки a tupleповертається, а потім порівнюється за рівність.

Мої запитання:

Це правильно? Чи є кращий спосіб зробити це? Краще не в швидкості, я кажу про елегантність коду.

ОНОВЛЕННЯ: Я забув зазначити, що я повинен перевірити, скільки key, valueпар рівні.


21
x == yмає бути вірно в відповідно до stackoverflow.com/a/5635309/186202
Natim

x == y має бути правдою. Можна швидко перевірити REPL. Перевірте: docs.python.org/2/library/stdtypes.html#mapping-types-dict
Вікрант

Відповіді:


179

Якщо ви хочете знати, скільки значень відповідають обом словникам, ви повинні сказати це :)

Можливо, щось подібне:

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

1
Та сама помилка, якщо є елемент списку для ключа dict. Я думаю, що cmp - кращий спосіб це зробити, якщо я нічого не пропускаю.
Мутант

@Mutant, це вже інше питання. Ви не можете створити словник з listключем в першу чергу. x = {[1,2]: 2}не вдасться. Питання вже є дійсним dicts.
AnnanFay

@annan: неправильно, питання є загальним. приклад в описі питання вже «дійсні dicts». Якщо я опублікую нове запитання, з такою ж назвою, але з іншим "недійсним" диктом, хтось позначить його як дублікат. Нахил
рибамар

6
@ribamar питання: "Порівняння двох словників [...]". Наведений вище "недійсний дикт" з listключами недійсний код python - ключі dict повинні бути незмінними. Тому ви не порівнюєте словники. Якщо ви спробуєте використати список як ключ словника, ваш код не запуститься. У вас немає об'єктів, з якими можна порівняти. Це як вводити x = dict(23\;dfg&^*$^%$^$%^)потім скарги, як порівняння не працює зі словником. Звичайно, це не вийде. Коментар Тіма, з іншого боку, стосується змінних values, тому я сказав, що це різні питання.
AnnanFay

1
@MikeyE - setвимагає, щоб значення були перебірними і dictвимагає перемикання ключів. set(x.keys())завжди працюватиме, тому що ключі повинні бути хешируемими, але set(x.values())не вдасться до значень, які не є хешируемими.
Тім Тісдалл

173

Що ви хочете зробити, це просто x==y

Те, що ви робите, - це не дуже гарна ідея, тому що пункти в словнику не повинні мати жодного порядку. Ви могли б бути по порівнянні [('a',1),('b',1)]з [('b',1), ('a',1)]( тим же словниками, різний порядку).

Наприклад, дивіться це:

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

Різниця лише в одному пункті, але ваш алгоритм побачить, що всі елементи різні


@ THC4k, вибачте, що не згадуєте. Але я повинен перевірити, скільки значень відповідають обом словникам.
user225312

Ок, так що, виходячи з мого оновлення, чи все ще неправильний спосіб моєї роботи?
user225312

@AA: Я додав, чому у вас не працює, коли ви хочете рахувати.
Йохен Рітцель

Я бачу, але в моєму випадку обидва словники однакової довжини. І вони завжди будуть, бо саме так працює програма.
user225312

5
Станом на Python 3.6, диктант впорядкований поза коробкою.
Філ

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
Цей фактично обробляє змінні значення в диктаті!
Тім Тісдалл

1
Коли я запускаю це, я все ще отримую помилку, бачачи справу зі змінними значеннями: ValueError: Значення істинності DataFrame неоднозначне. Використовуйте a.empty, a.bool (), a.item (), a.any () або a.all ().
Аффлатус

2
@Afflatus - DataFrames за дизайном не дозволяють порівнювати правдиві порівняння (якщо вони не мають довжини 1), оскільки вони успадковують numpy.ndarray. -credit до stackoverflow.com/a/33307396/994076
Даніель Майерс

Це абсолютний дорогоцінний камінь.
pfabri

125

dic1 == dic2

З Документів python :

Для ілюстрації наступні приклади все повертають словник рівний для {"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

Надання аргументів ключових слів, як у першому прикладі, працює лише для ключів, які є дійсними ідентифікаторами Python. В іншому випадку можна використовувати будь-які дійсні ключі.

Дійсно і для, py2і для py3.


3
Я не згоден з @ ErkinAlpGüney. Чи можете ви надати доказ?
Ци Луо

4
Я не згоден з @ ErkinAlpGüney. Офіційна документація показує, що == дійсно порівнює словники за значенням, а не за адресою. docs.python.org/2/library/stdtypes.html#mapping-types-dict
Метью Накаяма

3
Працює для Python 2.7.13
Єзуїзм

4
@ankostis:OrderedDict != dict
CONvid19

3
Чи можете ви надати інформацію, де це неправда?
CONvid19

55

Я новачок у python, але я в кінцевому підсумку робив щось подібне до @mouad

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

Оператор XOR ( ^) повинен усунути всі елементи дикту, коли вони однакові в обох диктах.


28
На жаль, це не спрацьовує, якщо значення в диктату є змінними (тобто не змішуються). (Екс {'a':{'b':1}}дає TypeError: unhashable type: 'dict')
Тім Тісдалл

54

Оскільки, здається, ніхто не згадав deepdiff, я додам його сюди для повноти. Мені дуже зручно отримувати різні (вкладені) об'єкти взагалі:

Установка

pip install deepdiff

Зразок коду

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

Вихідні дані

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

Зверніть увагу на гарне надрукування результату для перевірки: Наведений вище код працює, якщо обидва дикти мають однакові ключі атрибутів (з можливо різними значеннями атрибутів, як у прикладі). Однак якщо "extra"атрибут присутній в одному з диктів, json.dumps()не вдається

TypeError: Object of type PrettyOrderedSet is not JSON serializable

Рішення: використання diff.to_json()та json.loads()/ json.dumps()для симпатичного друку:

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

Вихід:

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

Альтернатива: використання pprint, результати в іншому форматуванні:

import pprint

# same code as above

pprint.pprint(diff, indent=4)

Вихід:

{   '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
Цікаво. Дякуємо, що відповіли на це. Корисний для мене щонайменше. Ця відповідь потребує більшої кількості результатів.
Архит Капур

46

Просто використовуйте:

assert cmp(dict1, dict2) == 0

6
Здається, що завдання полягає не лише у тому, щоб перевірити, чи вміст обох однаковий, але й дати звітність про відмінності
Дієго Терсеро

29
Я вважаю, що це ідентичноdict1 == dict2
Трей Ханнер

10
Для всіх, хто використовує Python3.5, cmpвбудований модуль було видалено (і слід ставитися до нього, як видалено раніше . Альтернативу, яку вони пропонують: (a > b) - (a < b) == cmp(a, b)для функціонального еквівалента (або краще __eq__і __hash__)
nerdwaller

3
@nerdwaller - дикти не є упорядкованими типами, тому dict_a> dict_b підніме TypeError:unorderable types: dict() < dict()
Стефано

2
@Stefano: Хороший дзвінок, мій коментар був більше для загального порівняння в python (я не звертав уваги на фактичну відповідь, моя помилка).
nerdwaller

9

Відповідь @mouad хороша, якщо ви припускаєте, що обидва словники містять лише прості значення. Однак якщо у вас є словники, які містять словники, ви отримаєте виняток, оскільки словники не є хешируемими.

У верхній частині моєї голови щось подібне може спрацювати:

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

Якщо ви використовуєте not isinstance(dict1, dict)замість цього type(dict1) is not dict, це буде працювати в інших класах на основі dict. Also, instead of (dict1 [key] == dict2 [key]) , you can do all (atleast_1d (dict1 [key] == dict2 [key])) `для обробки масивів принаймні.
EL_DON

+1, але ви можете вийти з нього, for loopяк тільки ваше dicts_are_equalстане помилковим. Не потрібно більше продовжувати.
pfabri

6

Ще одна можливість, до останньої ноти ОП, - порівняти хеши ( SHAабо MD) диктів, викинутих як JSON. Спосіб побудови хешей гарантує, що якщо вони рівні, то і рядки-джерела рівні. Це дуже швидко і математично добре.

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
Це абсолютно неправильно, просто аналіз даних у json дійсно повільний. Тоді хеширование тієї величезної свинги, яку ви тільки що створили, ще гірше. Ти ніколи цього не повинен робити
Бруно

7
@Bruno: цитуючи ОП: "Краще не в швидкості, я кажу про елегантність коду"
WoJ

2
Це зовсім не елегантно, він почуває себе небезпечно і надто складний для дійсно простої проблеми
Бруно

7
@Bruno: елегантність суб’єктивна. Я можу зрозуміти, що вам це не подобається (і, мабуть, прихильне). Це не те саме, що "неправильно".
WoJ

4
Це чудова відповідь. json.dumps(d, sort_keys=True)дасть вам канонічний JSON, щоб ви могли бути впевнені, що обидва дикта є рівнозначними. Також залежить те, що ви намагаєтеся досягти. Як тільки значення не буде серіалізаційним JSON, воно вийде з ладу. Тому що, хто каже, що це неефективно, подивіться на проект ujson.
Натім

6

Функція прекрасна IMO, чітка та інтуїтивна. Але тільки для того, щоб дати вам (ще одну) відповідь, ось мій шлях:

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

Може бути корисним для вас або для когось іншого ..

Редагувати:

Я створив рекурсивну версію вищезгаданої. Я не бачив цього в інших відповідях

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
Давайте вдосконалимо його, щоб воно працювало обома способами. Рядок 2: "для x1 у наборі (dict1.keys ()). Union (dict2.keys ()):"
nkadwa

Дякую @nkadwa, це робить зараз
zwep

5

Щоб перевірити, чи двоє диктів однакові в ключах і значеннях:

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)

Якщо ви хочете повернути значення, які відрізняються, запишіть їх по-різному:

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

Вам доведеться дзвонити це двічі, тобто

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

3

Код

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

Тест

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

3

Просте порівняння з == сьогодні повинно вистачити (python 3.8). Навіть коли ви порівнюєте ті самі дикти в іншому порядку (останній приклад). Найкраще, що для цього вам не потрібен сторонній пакет.

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

Запізнитися у моїй відповіді краще, ніж ніколи!

Порівняти Not_Equal є більш ефективним, ніж порівняння рівняння. Оскільки такі два дикти не є рівними, якщо жодних ключових значень в одному диктаті не знайдено в іншому диктаті. Код нижче враховує, що ви, можливо, порівнюєте дікт за замовчуванням і, таким чином, використовуєте get замість getitem [].

Використання в якості вибору випадкового значення за замовчуванням у виклику get, що дорівнює вилученому ключу, - на випадок, якщо в диктах значення "None" ("None") в одному диктаті, а в другому - немає. Крім того, умова get! = Перевіряється перед тим, що не є умовою ефективності, оскільки ви одночасно виконуєте перевірку клавіш та значень з обох сторін.

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

Я використовую це рішення, яке чудово працює для мене в 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

Він порівнює dict, list та будь-які інші типи, які реалізує оператор "==" самостійно. Якщо вам потрібно порівняти щось інше, вам потрібно додати нову гілку в "if дерево".

Сподіваюся, що це допомагає.


2

для 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'

Ось ще один варіант:

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

Отже, як ви бачите, ідентифікатори різні. Але, здається, багато операторів порівняння роблять цю справу:

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

У PyUnit існує метод, який гарно порівнює словники. Я перевірив це за допомогою наступних двох словників, і він робить саме те, що ви шукаєте.

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

Я не рекомендую імпортувати unittestу ваш виробничий код. Думаю, що джерело в PyUnit може бути повторно відтворено для запуску у виробництво. Він використовує, pprintякі "гарненько друкує" словники. Здається, досить легко адаптувати цей код, щоб він був готовий до виробництва.


1

див. об’єкти подання словника: https://docs.python.org/2/library/stdtypes.html#dict

Таким чином ви можете відняти dictView2 від dictView1, і він поверне набір пар ключів / значень, які відрізняються у 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')])

Ви можете перетинати, об'єднувати, відрізняти (показано вище), симетричну різницю цих об’єктів перегляду словника.
Краще? Швидше? - не впевнено, але частина стандартної бібліотеки - це робить великий плюс для портативності


1

Нижче код допоможе вам порівняти список дикту в python

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
Ласкаво просимо до переповнення стека! Хоча цей фрагмент коду може вирішити питання, у тому числі пояснення дійсно допомагає покращити якість вашої публікації. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду. Будь ласка, намагайтеся не переповнювати свій код пояснювальними коментарями, це зменшує читабельність і коду, і пояснень!
Фільнор

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

У Python 3.6 це можна зробити так:

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

ret змінна буде вірною, якщо всі елементи dict_1 присутні в dict_2


0

Ось моя відповідь, використовуйте рекурсивний спосіб:

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)

Сподіваюся, що це допомагає!


0

Чому б не просто повторити один словник і не перевірити інший у процесі (якщо обидва словники мають однакові ключі)?

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

Вихід:

Not 1 2
Ok 2 2

0

Найпростіший спосіб (і один із найнадійніших у цьому) зробити глибоке порівняння двох словників - це їх серіалізація у форматі JSON, сортування ключів та порівняння результатів рядків:

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
Це може не робити те, що було саме запитувано, і тягне за собою в json std lib, але це працює (як json.dumpsце детерміновано за налаштуваннями за замовчуванням).
Деніел Фаррелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.