두 개의 파이썬 사전에 포함 된 키의 차이 계산


171

- 내가 두 파이썬 사전을 가지고 있다고 가정 dictA하고 dictB. 에 dictB있지만 있지만 키가없는 키가 있는지 확인해야합니다 dictA. 가장 빠른 방법은 무엇입니까?

사전 키를 세트로 변환 한 다음 계속해야합니까?

당신의 생각을 알고 싶다 ...


답변 주셔서 감사합니다.

내 질문을 제대로 언급하지 않아서 죄송합니다. 내 시나리오는 다음과 같습니다-에 비해 dictAdictB거나 일부 키가 누락되었거나 키 dictB값이 다를 수있는 키 값이 다를 수 있습니다 dictA.

문제는 사전에 표준이 없으며 dict가 될 수있는 값을 가질 수 있다는 것입니다.

말하다

dictA={'key1':a, 'key2':b, 'key3':{'key11':cc, 'key12':dd}, 'key4':{'key111':{....}}}
dictB={'key1':a, 'key2:':newb, 'key3':{'key11':cc, 'key12':newdd, 'key13':ee}.......

따라서 'key2'값을 새 값으로 재설정하고 'key13'을 dict 안에 추가해야합니다. 키 값의 형식이 고정되어 있지 않습니다. 단순한 가치 또는 dict 또는 dict의 dict 일 수 있습니다.

답변:


234

키에서 설정 조작을 사용할 수 있습니다.

diff = set(dictb.keys()) - set(dicta.keys())

추가 된 항목, 제거 된 항목, 동일한 키-값 쌍 및 변경되는 키-값 쌍을 모두 찾을 수있는 클래스가 있습니다.

class DictDiffer(object):
    """
    Calculate the difference between two dictionaries as:
    (1) items added
    (2) items removed
    (3) keys same in both but changed values
    (4) keys same in both and unchanged values
    """
    def __init__(self, current_dict, past_dict):
        self.current_dict, self.past_dict = current_dict, past_dict
        self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys())
        self.intersect = self.set_current.intersection(self.set_past)
    def added(self):
        return self.set_current - self.intersect 
    def removed(self):
        return self.set_past - self.intersect 
    def changed(self):
        return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o])
    def unchanged(self):
        return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])

다음은 몇 가지 샘플 출력입니다.

>>> a = {'a': 1, 'b': 1, 'c': 0}
>>> b = {'a': 1, 'b': 2, 'd': 0}
>>> d = DictDiffer(b, a)
>>> print "Added:", d.added()
Added: set(['d'])
>>> print "Removed:", d.removed()
Removed: set(['c'])
>>> print "Changed:", d.changed()
Changed: set(['b'])
>>> print "Unchanged:", d.unchanged()
Unchanged: set(['a'])

github 저장소로 사용 가능 : https://github.com/hughdbrown/dictdiffer


3
똑똑한 솔루션, 감사합니다! 변경되거나 변경되지 않은 값이 dict 인스턴스인지 확인하고 재귀 함수를 호출하여 클래스를 사용하여 다시 확인하여 중첩 된 dicts와 함께 작동하도록했습니다.
AJJ

1
@ AJJ 나는 그 구현을보고 싶습니다.
urschrei

1
def update(self, new_dict): self.__init__(new_dict, self.current_dict)롤링 비교를 할 수 있도록 a 등은 어떻습니까
Nick T

몇 가지주의 사항 : DictDiffer클래스는 상태 비 저장 클래스이며 함수일 수 있습니다. changedunchanged값이 동일한 루프에서 계산 될 수있다. 이 두 함수는 a list대신에 a set를 반환 할 수 있습니다. 자세한 비교를 위해 단위 테스트 프레임 워크 인 docs.python.org/2/library/unittest.html을 살펴보고 assertDictEqual소스 코드 의 메소드를 따르십시오 .
Laurent LAPORTE

1
FWIW set(dictb)는 아마도보다 낫습니다 set(dictb.keys()).
mgilson

60

차이를 재귀 적으로 원한다면 파이썬 패키지를 작성했습니다 : https://github.com/seperman/deepdiff

설치

PyPi에서 설치 :

pip install deepdiff

사용법 예

가져 오기

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

동일한 객체가 비어 있음

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

아이템 유형이 변경되었습니다

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

아이템의 가치가 변경되었습니다

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

아이템 추가 및 / 또는 제거

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

문자열 차이

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

문자열 차이 2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

타입 변경

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

차이점

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

목록 차이 2 :

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

순서를 무시하거나 중복을 무시하는 차이점을 나열하십시오. (위와 동일한 사전으로)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

사전이 포함 된 목록 :

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

세트 :

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

명명 된 튜플 :

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

맞춤 객체 :

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

객체 속성이 추가되었습니다.

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

감사합니다! 내 프로젝트에서 구현되어 훌륭하게 작동합니다!
gtalarico 2016 년

1
@gtalarico 도와 드리겠습니다! 친절한 말 감사합니다!
Seperman

목록 순서 차이 를 무시하는 옵션이 있습니까? 내 응용 프로그램이 신경 쓰지 않기 때문입니다.
Lei Yang

좋은 프로젝트, 내 편에서 최소한의 노력으로 모든 일을했다. 감사!
Stanislav Tsepa

@LeiYang 예 ignore_order=True. 설정할 수 있습니다 . deepdiff.readthedocs.io/en/latest/diff.html
Seperman

18

"빠른"지 아닌지 확실하지 않지만 일반적 으로이 작업을 수행 할 수 있습니다

dicta = {"a":1,"b":2,"c":3,"d":4}
dictb = {"a":1,"d":2}
for key in dicta.keys():
    if not key in dictb:
        print key

당신은 교환해야 dicta하고 dictb그는 dictb에없는 그 키를 알고 싶어하기 때문에 dicta.
Gumbo

2
for key in dicta.keys():=>for key in dicta:
Jean-François Fabre

15

Alex Martelli가 쓴 것처럼 B의 키가 A가 아닌지 확인하고 싶다면 any(True for k in dictB if k not in dictA) .

누락 된 키를 찾으려면 다음을 수행하십시오.

diff = set(dictB)-set(dictA) #sets

C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA =    
dict(zip(range(1000),range
(1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=set(dictB)-set(dictA)"
10000 loops, best of 3: 107 usec per loop

diff = [ k for k in dictB if k not in dictA ] #lc

C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA = 
dict(zip(range(1000),range
(1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=[ k for k in dictB if
k not in dictA ]"
10000 loops, best of 3: 95.9 usec per loop

따라서이 두 솔루션은 거의 같은 속도입니다.


8
이것은 더 의미가 있습니다 :any(k not in dictA for k in dictB)
hughdbrown

13

당신이 말한 것을 정확히 의미한다면 (만약 A가 아닌 B에 "어떤 키가 있는지"만 알아 내면된다. 어떤 것이 있을지 모른다) 가장 빠른 방법은 다음과 같아야한다.

if any(True for k in dictB if k not in dictA): ...

WHICH KEYS (있는 경우)가 B에 있고 A가 아닌 "IF"가 아니라는 사실을 찾아야하는 경우, 그러한 키가있는 경우 기존 답변이 매우 적합합니다 (그러나 다음 질문에 대해서는 향후 질문에서 더 정밀하게 제안합니다) 실제로 당신이 의미하는 바 ;-).



8

hughdbrown의 최고 답변은 차이를 사용하는 것이 좋습니다.

diff = set(dictb.keys()) - set(dicta.keys())

이 코드의 문제점은 두 세트를 만들기 위해 두 개의 목록을 작성하므로 4N 시간과 2N 공간을 낭비한다는 것입니다. 또한 필요한 것보다 조금 더 복잡합니다.

일반적으로 이것은 큰 문제는 아니지만 다음과 같은 경우 :

diff = dictb.keys() - dicta

파이썬 2

Python 2에서는 keys()키가 아닌 키 목록을 반환합니다 KeysView. 따라서 viewkeys()직접 요청해야 합니다.

diff = dictb.viewkeys() - dicta

이중 버전 2.7 / 3.x 코드의 경우 six다음을 사용할 수 있기를 바랍니다 six.viewkeys(dictb).

diff = six.viewkeys(dictb) - dicta

2.4-2.6에는가 없습니다 KeysView. 그러나 먼저 목록을 작성하는 대신 왼쪽 세트를 반복기에서 직접 빌드하여 4N에서 N으로 비용을 줄일 수 있습니다.

diff = set(dictb) - dicta

아이템

dictB와 같을 수있는 dictA가 있거나 dictB에 비해 일부 키가 누락되었거나 일부 키의 값이 다를 수 있습니다

따라서 실제로 키와 항목을 비교할 필요는 없습니다. 은 ItemsView단지이다 Set값이 문자열과 같은 해쉬 경우. 그들이 쉬운 경우 :

diff = dictb.items() - dicta.items()

재귀 diff

질문이 재귀 diff를 직접 요구하지는 않지만 일부 예제 값은 dict이며 예상되는 출력은 재귀 적으로 diff합니다. 그 방법을 보여주는 여러 답변이 이미 있습니다.


2018 년에서 확답
장 - 프랑수아 파브르

@ Jean-FrançoisFabre 물론 파이썬 2.4-2.6은 2018 년과 관련이 없습니다…
abarnert

일부 사람들은 2.6
Jean-François Fabre에


3

다음은 작동하는 방법으로 평가하는 키를 허용하며 False가능한 경우 생성기 표현식을 사용하여 조기에 빠지는 방법입니다. 그래도 예외는 아닙니다.

any(map(lambda x: True, (k for k in b if k not in a)))

편집하다:

THC4k가 다른 답변에 대한 내 의견에 답글을 올렸습니다. 위의 작업을 수행하는 더 좋고 더 좋은 방법이 있습니다.

any(True for k in b if k not in a)

그것이 어떻게 내 마음을 넘지 못했는지 확실하지 않습니다 ...


이것은 이전의 Alex Martelli의 답변과 동일합니다
Jean-François Fabre

지금이야. 내가 그것을 게시했을 때 (9 년 전, lol) 이전의 대답은 any(k for k in dictB if k not in dictA)(거짓 키의 경우) 똑같지 않았습니다. 편집 이력 / 타임 스탬프를 확인하십시오.
Steve Losh

3

이것은 오래된 질문이며 필요한 것보다 조금 덜 묻기 때문에이 답변은 실제로이 질문보다 더 많이 해결됩니다. 이 질문에 대한 답변은 다음을 해결하는 데 도움이되었습니다.

  1. (필수) 두 사전 사이의 레코드 차이
  2. # 1과의 차이점을 기본 사전에 병합
  3. (필수) 두 사전 간의 차이점 병합 (사전 # 2를 마치 사전 사전 인 것처럼 처리)
  4. 변경 사항뿐만 아니라 항목 이동을 감지하십시오.
  5. 이 질문을 모두 재귀 적으로 수행하십시오.

이 모든 것을 JSON과 결합하면 매우 강력한 구성 저장소 지원이 가능합니다.

해결책 ( github ) :

from collections import OrderedDict
from pprint import pprint


class izipDestinationMatching(object):
    __slots__ = ("attr", "value", "index")

    def __init__(self, attr, value, index):
        self.attr, self.value, self.index = attr, value, index

    def __repr__(self):
        return "izip_destination_matching: found match by '%s' = '%s' @ %d" % (self.attr, self.value, self.index)


def izip_destination(a, b, attrs, addMarker=True):
    """
    Returns zipped lists, but final size is equal to b with (if shorter) a padded with nulls
    Additionally also tries to find item reallocations by searching child dicts (if they are dicts) for attribute, listed in attrs)
    When addMarker == False (patching), final size will be the longer of a, b
    """
    for idx, item in enumerate(b):
        try:
            attr = next((x for x in attrs if x in item), None)  # See if the item has any of the ID attributes
            match, matchIdx = next(((orgItm, idx) for idx, orgItm in enumerate(a) if attr in orgItm and orgItm[attr] == item[attr]), (None, None)) if attr else (None, None)
            if match and matchIdx != idx and addMarker: item[izipDestinationMatching] = izipDestinationMatching(attr, item[attr], matchIdx)
        except:
            match = None
        yield (match if match else a[idx] if len(a) > idx else None), item
    if not addMarker and len(a) > len(b):
        for item in a[len(b) - len(a):]:
            yield item, item


def dictdiff(a, b, searchAttrs=[]):
    """
    returns a dictionary which represents difference from a to b
    the return dict is as short as possible:
      equal items are removed
      added / changed items are listed
      removed items are listed with value=None
    Also processes list values where the resulting list size will match that of b.
    It can also search said list items (that are dicts) for identity values to detect changed positions.
      In case such identity value is found, it is kept so that it can be re-found during the merge phase
    @param a: original dict
    @param b: new dict
    @param searchAttrs: list of strings (keys to search for in sub-dicts)
    @return: dict / list / whatever input is
    """
    if not (isinstance(a, dict) and isinstance(b, dict)):
        if isinstance(a, list) and isinstance(b, list):
            return [dictdiff(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs)]
        return b
    res = OrderedDict()
    if izipDestinationMatching in b:
        keepKey = b[izipDestinationMatching].attr
        del b[izipDestinationMatching]
    else:
        keepKey = izipDestinationMatching
    for key in sorted(set(a.keys() + b.keys())):
        v1 = a.get(key, None)
        v2 = b.get(key, None)
        if keepKey == key or v1 != v2: res[key] = dictdiff(v1, v2, searchAttrs)
    if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
    return res


def dictmerge(a, b, searchAttrs=[]):
    """
    Returns a dictionary which merges differences recorded in b to base dictionary a
    Also processes list values where the resulting list size will match that of a
    It can also search said list items (that are dicts) for identity values to detect changed positions
    @param a: original dict
    @param b: diff dict to patch into a
    @param searchAttrs: list of strings (keys to search for in sub-dicts)
    @return: dict / list / whatever input is
    """
    if not (isinstance(a, dict) and isinstance(b, dict)):
        if isinstance(a, list) and isinstance(b, list):
            return [dictmerge(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs, False)]
        return b
    res = OrderedDict()
    for key in sorted(set(a.keys() + b.keys())):
        v1 = a.get(key, None)
        v2 = b.get(key, None)
        #print "processing", key, v1, v2, key not in b, dictmerge(v1, v2)
        if v2 is not None: res[key] = dictmerge(v1, v2, searchAttrs)
        elif key not in b: res[key] = v1
    if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
    return res

2

표준은 어떻습니까 (FULL Object 비교)

PyDev-> 새로운 PyDev 모듈-> 모듈 : unittest

import unittest


class Test(unittest.TestCase):


    def testName(self):
        obj1 = {1:1, 2:2}
        obj2 = {1:1, 2:2}
        self.maxDiff = None # sometimes is usefull
        self.assertDictEqual(d1, d2)

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']

    unittest.main()

거대한 중첩 사전이 있고 내부의 모든 것을 비교하고 차이점을보고 싶을 때 이것은 훌륭합니다. 감사!
Matthew Moisen

2

Python ≥ 2.7 인 경우 :

# update different values in dictB
# I would assume only dictA should be updated,
# but the question specifies otherwise

for k in dictA.viewkeys() & dictB.viewkeys():
    if dictA[k] != dictB[k]:
        dictB[k]= dictA[k]

# add missing keys to dictA

dictA.update( (k,dictB[k]) for k in dictB.viewkeys() - dictA.viewkeys() )

1

다음은 2 개의 사전 키를 심층적으로 비교하는 솔루션입니다.

def compareDictKeys(dict1, dict2):
  if type(dict1) != dict or type(dict2) != dict:
      return False

  keys1, keys2 = dict1.keys(), dict2.keys()
  diff = set(keys1) - set(keys2) or set(keys2) - set(keys1)

  if not diff:
      for key in keys1:
          if (type(dict1[key]) == dict or type(dict2[key]) == dict) and not compareDictKeys(dict1[key], dict2[key]):
              diff = True
              break

  return not diff

1

다음은 두 가지 이상의 dict을 비교할 수있는 솔루션입니다.

def diff_dict(dicts, default=None):
    diff_dict = {}
    # add 'list()' around 'd.keys()' for python 3 compatibility
    for k in set(sum([d.keys() for d in dicts], [])):
        # we can just use "values = [d.get(k, default) ..." below if 
        # we don't care that d1[k]=default and d2[k]=missing will
        # be treated as equal
        if any(k not in d for d in dicts):
            diff_dict[k] = [d.get(k, default) for d in dicts]
        else:
            values = [d[k] for d in dicts]
            if any(v != values[0] for v in values):
                diff_dict[k] = values
    return diff_dict

사용 예 :

import matplotlib.pyplot as plt
diff_dict([plt.rcParams, plt.rcParamsDefault, plt.matplotlib.rcParamsOrig])

1

두 사전 간의 대칭 차이에 대한 나의 요리법 :

def find_dict_diffs(dict1, dict2):
    unequal_keys = []
    unequal_keys.extend(set(dict1.keys()).symmetric_difference(set(dict2.keys())))
    for k in dict1.keys():
        if dict1.get(k, 'N\A') != dict2.get(k, 'N\A'):
            unequal_keys.append(k)
    if unequal_keys:
        print 'param', 'dict1\t', 'dict2'
        for k in set(unequal_keys):
            print str(k)+'\t'+dict1.get(k, 'N\A')+'\t '+dict2.get(k, 'N\A')
    else:
        print 'Dicts are equal'

dict1 = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'}
dict2 = {1:'b', 2:'a', 3:'c', 4:'d', 6:'f'}

find_dict_diffs(dict1, dict2)

결과는 다음과 같습니다.

param   dict1   dict2
1       a       b
2       b       a
5       e       N\A
6       N\A     f

1

다른 답변에서 언급했듯이 unittest는 dicts를 비교하기위한 좋은 결과를 생성하지만이 예제에서는 전체 테스트를 먼저 빌드하지 않아도됩니다.

unittest 소스를 긁어 내면 다음과 같이 공정한 솔루션을 얻을 수있는 것처럼 보입니다.

import difflib
import pprint

def diff_dicts(a, b):
    if a == b:
        return ''
    return '\n'.join(
        difflib.ndiff(pprint.pformat(a, width=30).splitlines(),
                      pprint.pformat(b, width=30).splitlines())
    )

그래서

dictA = dict(zip(range(7), map(ord, 'python')))
dictB = {0: 112, 1: 'spam', 2: [1,2,3], 3: 104, 4: 111}
print diff_dicts(dictA, dictB)

결과 :

{0: 112,
-  1: 121,
-  2: 116,
+  1: 'spam',
+  2: [1, 2, 3],
   3: 104,
-  4: 111,
?        ^

+  4: 111}
?        ^

-  5: 110}

어디:

  • '-'는 첫 번째이지만 두 번째 dict의 키 / 값을 나타냅니다.
  • '+'는 첫 번째 dict가 아닌 두 번째 키 / 값을 나타냅니다.

unittest와 마찬가지로, 유일한 쉼표는 후행 쉼표 / ​​괄호로 인해 최종 매핑이 diff로 간주 될 수 있다는 것입니다.


1

@Maxx에는 훌륭한 답변이 있습니다 .Python에서 unittest제공 하는 도구를 사용하십시오 .

import unittest


class Test(unittest.TestCase):
    def runTest(self):
        pass

    def testDict(self, d1, d2, maxDiff=None):
        self.maxDiff = maxDiff
        self.assertDictEqual(d1, d2)

그런 다음 코드의 어느 곳에서나 전화 할 수 있습니다.

try:
    Test().testDict(dict1, dict2)
except Exception, e:
    print e

결과 출력은의 출력과 유사하며 diff, 각 행마다 사전을 인쇄 +하거나 -다른 행을 앞에 추가합니다.


0

그것이 여전히 관련이 있는지 확실하지 않지만이 문제를 겪었습니다. 내 상황은 모든 중첩 사전 등의 변경 사항 사전을 반환해야했습니다. 좋은 해결책을 찾을 수는 없지만 간단한 함수를 작성했습니다. 이것을하기 위해 . 도움이 되었기를 바랍니다,


2
링크 대신 실제로 답변에서 OP의 문제를 해결하는 가장 적은 양의 코드를 사용하는 것이 좋습니다. 링크가 끊어 지거나 움직이면 답이 쓸모 없게됩니다.
George Stocker

0

임의의 dict 구조와의 완벽한 비교를 위해 내장 솔루션을 원한다면 @Maxx의 대답이 좋습니다.

import unittest

test = unittest.TestCase()
test.assertEqual(dictA, dictB)

분명히 테스트 클래스를 인스턴스화 할 수는 없으므로 너무 나쁩니다.
Ben Liyanage

0

ghostdog74의 답변을 바탕으로

dicta = {"a":1,"d":2}
dictb = {"a":5,"d":2}

for value in dicta.values():
    if not value in dictb.values():
        print value

dicta의 다른 값을 인쇄합니다


0

두 가지 사전에있는 키인 교차점을 찾으려면 이것을 시도하십시오. 두 번째 사전에없는 키를 원한다면 not in ...

intersect = filter(lambda x, dictB=dictB.keys(): x in dictB, dictA.keys())
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.