Сравнение двух словарей в Python - PullRequest
205 голосов
/ 24 декабря 2010

У меня есть два словаря, но для упрощения я возьму эти два:

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

И это работает, поскольку tuple возвращается и затем сравнивается на равенство.

Мои вопросы:

Это правильно?Есть ли лучший способ сделать это?Лучше не в скорости, я говорю об элегантности кода.

ОБНОВЛЕНИЕ: я забыл упомянуть, что я должен проверить, сколько пар key, value равны.

Ответы [ 22 ]

3 голосов
/ 05 февраля 2017

Код

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 голосов
/ 02 мая 2018

Функция отлично 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')

Может быть полезным для вас или для кого-либо еще ..

2 голосов
/ 21 января 2019

Я использую это решение, которое отлично работает для меня в 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 и любые другие типы, которые самостоятельно реализуют оператор "==".Если вам нужно сравнить что-то другое, вам нужно добавить новую ветку в «если дерево».

Надеюсь, что это поможет.

1 голос
/ 09 августа 2017

см. Словарь просмотра объектов: 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 голос
/ 20 февраля 2014
>>> 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 голос
/ 10 апреля 2017

В 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 голос
/ 19 декабря 2018

Опоздание в моем ответе лучше, чем никогда!

Сравнение Not_Equal более эффективно, чем сравнение Equal. Как таковые, два диктата не равны, если какие-либо ключевые значения в одном из них не найдены в другом. Приведенный ниже код учитывает, что вы, возможно, сравниваете dict по умолчанию и, следовательно, используете get вместо getitem [].

Использование вида случайного значения в качестве значения по умолчанию при вызове get, равного ключу, который нужно получить - на тот случай, если у dicts значение 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)
1 голос
/ 04 декабря 2018

Ниже код поможет вам сравнить список dict в 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
0 голосов
/ 15 марта 2019
>>> 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 голосов
/ 02 апреля 2016
import json

if json.dumps(dict1) == json.dumps(dict2):
    print("Equal")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...