Как получить разницу между двумя словарями в Python?

У меня есть два словаря. Мне нужно найти разницу между двумя, которые должны дать мне ключ и значение.

Я искал и нашел несколько аддонов/пакетов, таких как datadiff, dictdiff-master, но когда я попробую его в Python 2.7, он говорит, что такой модуль не определен.

Я использовал здесь.

first_dict = {}
second_dict = {}

value = set(second_dict)-set(first_dict)
print value

output → > set (['SCD-3547', 'SCD-3456'])

Я получаю только ключ, мне нужно даже получить значения.

Ответ 1

Попробуйте следующий фрагмент, используя понимание словаря:

value = { k : second_dict[k] for k in set(second_dict) - set(first_dict) }

В приведенном выше коде мы находим разницу в ключах, а затем восстанавливаем dict, принимая соответствующие значения.

Ответ 2

Я думаю, что для этого лучше использовать симметричную разностную операцию множеств . Вот ссылка на документ.

>>> dict1 = {1:'donkey', 2:'chicken', 3:'dog'}
>>> dict2 = {1:'donkey', 2:'chimpansee', 4:'chicken'}
>>> set1 = set(dict1.items())
>>> set2 = set(dict2.items())
>>> set1 ^ set2
{(2, 'chimpansee'), (4, 'chicken'), (2, 'chicken'), (3, 'dog')}

Это симметрично, потому что:

>>> set2 ^ set1
{(2, 'chimpansee'), (4, 'chicken'), (2, 'chicken'), (3, 'dog')}

Это не тот случай, когда используется оператор разницы.

>>> set1 - set2
{(2, 'chicken'), (3, 'dog')}
>>> set2 - set1
{(2, 'chimpansee'), (4, 'chicken')}

Однако преобразование полученного набора в словарь может быть не очень хорошей идеей, поскольку вы можете потерять информацию:

>>> dict(set1 ^ set2)
{2: 'chicken', 3: 'dog', 4: 'chicken'}

Ответ 3

Другим решением будет dictdiffer (https://github.com/inveniosoftware/dictdiffer).

import dictdiffer                                          

a_dict = {                                                 
  'a': 'foo',
  'b': 'bar',
  'd': 'barfoo'
}                                                          

b_dict = {                                                 
  'a': 'foo',                                              
  'b': 'BAR',
  'c': 'foobar'
}                                                          

for diff in list(dictdiffer.diff(a_dict, b_dict)):         
    print diff

Разница - это кортеж с типом изменения, измененным значением и путем к записи.

('change', 'b', ('bar', 'BAR'))
('add', '', [('c', 'foobar')])
('remove', '', [('d', 'barfoo')])

Ответ 4

Вы были правы, глядя на использование набора, нам просто нужно немного углубиться, чтобы заставить ваш метод работать.

Во-первых, код примера:

test_1 = {"foo": "bar", "FOO": "BAR"}
test_2 = {"foo": "bar", "f00": "[email protected]"}

Мы видим, что оба словаря содержат аналогичную пару ключ/значение:

{"foo": "bar", ...}

В каждом словаре также содержится совершенно другая пара значений ключа. Но как мы обнаруживаем разницу? Словари этого не поддерживают. Вместо этого вы захотите использовать набор.

Вот как превратить каждый словарь в набор, который мы можем использовать:

set_1 = set(test_1.items())
set_2 = set(test_2.items())

Это возвращает набор, содержащий ряд кортежей. Каждый кортеж представляет собой одну пару ключ/значение из вашего словаря.

Теперь, чтобы найти разницу между set_1 и set_2:

print set_1 - set_2
>>> {('FOO', 'BAR')}

Хотите вернуть словарь? Просто, просто:

dict(set_1 - set_2)
>>> {'FOO': 'BAR'}

Ответ 5

Эта функция предоставляет вам все различия (и то, что осталось прежним) только на основе ключей словаря. Он также выделяет некоторые хорошие возможности Dict, операции Set и аннотации типа python 3.6 :)

def get_dict_diffs(a: Dict[str, Any], b: Dict[str, Any]) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any], Dict[str, Any]]:

    added_to_b_dict: Dict[str, Any] = {k: b[k] for k in set(b) - set(a)}
    removed_from_a_dict: Dict[str, Any] = {k: a[k] for k in set(a) - set(b)}
    common_dict_a: Dict[str, Any] = {k: a[k] for k in set(a) & set(b)}
    common_dict_b: Dict[str, Any] = {k: b[k] for k in set(a) & set(b)}
    return added_to_b_dict, removed_from_a_dict, common_dict_a, common_dict_b

Если вы хотите сравнить значения словаря:

values_in_b_not_a_dict = {k : b[k] for k, _ in set(b.items()) - set(a.items())}

Ответ 6

Как насчет этого? Не так красиво, но явно.

orig_dict = {'a' : 1, 'b' : 2}
new_dict = {'a' : 2, 'v' : 'hello', 'b' : 2}

updates = {}
for k2, v2 in new_dict.items():
    if k2 in orig_dict:    
        if v2 != orig_dict[k2]:
            updates.update({k2 : v2})
    else:
        updates.update({k2 : v2})

#test it
#value of 'a' was changed
#'v' is a completely new entry
assert all(k in updates for k in ['a', 'v'])

Ответ 7

def flatten_it(d):
    if isinstance(d, list) or isinstance(d, tuple):
        return tuple([flatten_it(item) for item in d])
    elif isinstance(d, dict):
        return tuple([(flatten_it(k), flatten_it(v)) for k, v in sorted(d.items())])
    else:
        return d

dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'a': 1, 'b': 1}

print set(flatten_it(dict1)) - set(flatten_it(dict2)) # set([('b', 2), ('c', 3)])
# or 
print set(flatten_it(dict2)) - set(flatten_it(dict1)) # set([('b', 1)])