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

– 내가 두 파이썬 사전을 가지고 있다고 가정 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 일 수 있습니다.



답변

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

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


답변

차이를 재귀 적으로 원한다면 파이썬 패키지를 작성했습니다 :
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}}}


답변

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

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


답변

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

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


답변

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

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

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


답변

사용set() :

set(dictA.keys()).intersection(dictB.keys())


답변

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합니다. 그 방법을 보여주는 여러 답변이 이미 있습니다.