파이썬에서 두 사전의 차이를 얻는 방법은 무엇입니까?
저는 두 개의 사전을 가지고 있고, 두 개의 차이점을 찾아야 하는데, 그것은 저에게 열쇠와 가치를 둘 다 줄 것입니다.
datadiff, dictdiff-master와 같은 추가/패키지를 검색하여 찾았는데, Python 2.7에서 가져오려고 하면 해당 모듈이 정의되어 있지 않다고 나옵니다.
나는 여기서 세트를 사용했습니다.
first_dict = {}
second_dict = {}
value = set(second_dict) - set(first_dict)
print value
내 출력은 다음과 같습니다.
>>> set(['SCD-3547', 'SCD-3456'])
저는 열쇠만 받고 있고, 값도 받아야 합니다.
그러기 위해서는 집합의 대칭적인 차이 연산을 사용하는 것이 좋다고 생각합니다. 여기 문서에 대한 링크가 있습니다.
>>> 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'}
사전 이해를 사용하여 다음 스니펫을 시도해 보십시오.
value = { k : second_dict[k] for k in set(second_dict) - set(first_dict) }
위의 코드에서 우리는 키의 차이를 찾은 다음 다시 작성합니다.dict
해당하는 값을 취합니다.
다른 은 또다해은책결입니다.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
diff는 변경 유형, 변경된 값 및 항목의 경로를 가진 튜플입니다.
('change', 'b', ('bar', 'BAR'))
('add', '', [('c', 'foobar')])
('remove', '', [('d', 'barfoo')])
DeepDiff를 사용할 수 있습니다.
pip install deepdiff
특히 사전, 반복 가능한 항목, 문자열 및 기타 개체의 차이를 재귀적으로 계산할 수 있습니다.
>>> from deepdiff import DeepDiff
>>> d1 = {1:1, 2:2, 3:3, "foo":4}
>>> d2 = {1:1, 2:4, 3:3, "bar":5, 6:6}
>>> DeepDiff(d1, d2)
{'dictionary_item_added': [root['bar'], root[6]],
'dictionary_item_removed': [root['foo']],
'values_changed': {'root[2]': {'new_value': 4, 'old_value': 2}}}
변경된 항목(짝수 유형), 추가된 항목 및 제거된 항목을 볼 수 있습니다.또한 중복을 무시하고 경로를 무시하는 등의 다양한 작업을 수행할 수 있습니다(정규식으로 정의됨).
해결책은 다음을 사용하는 것입니다.unittest
모듈:
from unittest import TestCase
TestCase().assertDictEqual(expected_dict, actual_dict)
에서 얻은 두 개의 사전이 파이썬에서 파이테스트와 동일한지 테스트할 수 있는 방법
세트를 사용하는 것을 보는 것이 옳았습니다, 우리는 당신의 방법을 작동시키기 위해 조금 더 깊이 파고들 필요가 있습니다.
먼저 예제 코드:
test_1 = {"foo": "bar", "FOO": "BAR"}
test_2 = {"foo": "bar", "f00": "b@r"}
두 사전에 모두 유사한 키/값 쌍이 포함되어 있음을 확인할 수 있습니다.
{"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'}
저는 좋은 개발자들이 이미 작성한 것을 사용하는 것을 추천합니다.맘에 들다pytest
그것은 딕트뿐만 아니라 모든 데이터 유형과 거래합니다.BTW, 그고리 BTW,pytest
테스트를 매우 잘합니다.
from _pytest.assertion.util import _compare_eq_any
print('\n'.join(_compare_eq_any({'a': 'b'}, {'aa': 'vv'}, verbose=3)))
출력:
Left contains 1 more item:
{'a': 'b'}
Right contains 1 more item:
{'aa': 'vv'}
Full diff:
- {'aa': 'vv'}
? - ^^
+ {'a': 'b'}
? ^
기능을 하는 것이 (으로 )_
), 의 코드에 하십시오.), "Copy/Copy"입니다.
추신: 테트대로 pytest==6.2.4
다른 답변에 언급된 것처럼 대칭 차분 집합 연산자를 사용하는 함수로, 값의 원점을 보존합니다.
def diff_dicts(a, b, missing=KeyError):
"""
Find keys and values which differ from `a` to `b` as a dict.
If a value differs from `a` to `b` then the value in the returned dict will
be: `(a_value, b_value)`. If either is missing then the token from
`missing` will be used instead.
:param a: The from dict
:param b: The to dict
:param missing: A token used to indicate the dict did not include this key
:return: A dict of keys to tuples with the matching value from a and b
"""
return {
key: (a.get(key, missing), b.get(key, missing))
for key in dict(
set(a.items()) ^ set(b.items())
).keys()
}
예
print(diff_dicts({'a': 1, 'b': 1}, {'b': 2, 'c': 2}))
# {'c': (<class 'KeyError'>, 2), 'a': (1, <class 'KeyError'>), 'b': (1, 2)}
작동 방식
우리는 항목을 취하면서 생성된 튜플에 대칭 차이 집합 연산자를 사용합니다.의 구별되는 합니다.(key, value)
두 받아쓰기의 튜플
그런 다음 새로운 명령어를 만들어 키를 함께 접고 반복합니다.이 키들은 하나의 딕트에서 다음 딕트로 변경된 유일한 키입니다.
그런 다음 이러한 키를 사용하여 키가 없을 때 누락된 토큰을 대체하는 각 딕트의 값 튜플과 함께 새 딕트를 구성합니다.
이 기능은 사전 키만을 기준으로 모든 차이(및 동일하게 유지된 차이)를 제공합니다.또한 일부 멋진 딕트 이해, 세트 작업 및 파이썬 3.6 유형 주석을 강조합니다 :)
from typing import Dict, Any, Tuple
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())}
이것은 https://stackoverflow.com/a/67263119/919692 과 https://stackoverflow.com/a/48544451/919692, 을 결합한 저만의 버전이며, 이제 https://stackoverflow.com/a/47433207/919692 과 상당히 유사하다는 것을 알게 되었습니다.
def dict_diff(dict_a, dict_b, show_value_diff=True):
result = {}
result['added'] = {k: dict_b[k] for k in set(dict_b) - set(dict_a)}
result['removed'] = {k: dict_a[k] for k in set(dict_a) - set(dict_b)}
if show_value_diff:
common_keys = set(dict_a) & set(dict_b)
result['value_diffs'] = {
k:(dict_a[k], dict_b[k])
for k in common_keys
if dict_a[k] != dict_b[k]
}
return result
이것이 OP가 요구한 것인지는 확실하지 않지만, 제가 이 질문을 접했을 때 찾고 있던 것입니다. 구체적으로, 키별로 두 딕트의 차이를 보여주는 방법입니다.
Pitfall: 하나의 딕트에 누락된 키가 있고 두 번째 딕트에 없음 값이 있을 때 함수는 그들이 유사하다고 가정합니다.
이것은 전혀 최적화되지 않았습니다. 작은 딕트에 적합합니다.
def diff_dicts(a, b, drop_similar=True):
res = a.copy()
for k in res:
if k not in b:
res[k] = (res[k], None)
for k in b:
if k in res:
res[k] = (res[k], b[k])
else:
res[k] = (None, b[k])
if drop_similar:
res = {k:v for k,v in res.items() if v[0] != v[1]}
return res
print(diff_dicts({'a': 1}, {}))
print(diff_dicts({'a': 1}, {'a': 2}))
print(diff_dicts({'a': 2}, {'a': 2}))
print(diff_dicts({'a': 2}, {'b': 2}))
print(diff_dicts({'a': 2}, {'a': 2, 'b': 1}))
출력:
{'a': (1, None)}
{'a': (1, 2)}
{}
{'a': (2, None), 'b': (None, 2)}
{'b': (None, 1)}
이건 어때요?그렇게 예쁘지는 않지만 노골적입니다.
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'])
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)])
오래된 질문이지만 어쨌든 해결책을 공유해야겠다고 생각했습니다.아주 간단합니다.
dicta_set = set(dicta.items()) # creates a set of tuples (k/v pairs)
dictb_set = set(dictb.items())
setdiff = dictb_set.difference(dicta_set) # any set method you want for comparisons
for k, v in setdiff: # unpack the tuples for processing
print(f"k/v differences = {k}: {v}")
이 코드는 k/v 쌍을 나타내는 두 개의 튜플 세트를 생성합니다.그런 다음 선택한 설정된 방법을 사용하여 튜플을 비교합니다.마지막으로 처리를 위해 튜플(k/v 쌍)의 포장을 풉니다.
새 딕트(변경된 데이터만)가 반환됩니다.
def get_difference(obj_1: dict, obj_2: dict) -> dict:
result = {}
for key in obj_1.keys():
value = obj_1[key]
if isinstance(value, dict):
difference = get_difference(value, obj_2.get(key, {}))
if difference:
result[key] = difference
elif value != obj_2.get(key):
result[key] = obj_2.get(key, None)
return result
한쪽 비교를 위해 딕트 이해를 사용할 수 있습니다.
dict1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
dict2 = {'a': OMG, 'b': 2, 'c': 3, 'd': 4}
data = {a:dict1[a] for a in dict1 if dict1[a] != dict2[a]}
출력: {'a': 1}
다음은 dict2의 값이 올바른 경우 dict1 값을 업데이트할 수 있는 변형입니다.
고려 사항:
dict1.update((k, dict2.get(k)) for k, v in dict1.items())
a_dic={'a':1, 'b':2}
b_dic={'a':1, 'b':20}
sharedmLst = set(a_dic.items()).intersection(b_dic.items())
diff_from_b = set(a_dic.items()) - sharedmLst
diff_from_a = set(b_dic.items()) - sharedmLst
print("Among the items in a_dic, the item different from b_dic",diff_from_b)
print("Among the items in b_dic, the item different from a_dic",diff_from_a)
Result :
Among the items in a_dic, the item different from b_dic {('b', 2)}
Among the items in b_dic, the item different from a_dic {('b', 20)}
이 솔루션은 해시할 수 없는 딕트와 완벽하게 작동하여 다음 오류를 해결합니다.
TypeError: Unhashable type 'dict'.
@Roedy의 최상위 솔루션부터 시작하십시오.목록 사전을 만듭니다. 이 사전은 해시할 수 없는 목록의 좋은 예입니다.
>>> dict1 = {1:['donkey'], 2:['chicken'], 3:['dog']}
>>> dict2 = {1:['donkey'], 2:['chimpansee'], 4:['chicken']}
그런 다음 다음 다음을 사용하여 각 값을 해시할 수 있도록 사전 처리합니다.str(value)
:
>>> set1 = set([(key, str(value)) for key, value in dict1.items()])
>>> set2 = set([(key, str(value)) for key, value in dict2.items()])
그런 다음 @Reody의 답변에 따라 계속 진행합니다.
>>> set1 ^ set2
{(3, "['dog']"), (4, "['chicken']"), (2, "['chimpansee']"), (2,"['chicken']")}
테스트를 위해 데이터 테스트 패키지는 사전, numpy 배열, 팬더 데이터 프레임 등의 차이를 확인합니다.데이터 검정을 사용하면 부동 소수점 비교에 대한 공차도 설정할 수 있습니다.
from datatest import validate, accepted
def test_compare_dict():
expected = {"key1": 0.5}
actual = {"key1": 0.499}
with accepted.tolerance(0.1):
validate(expected, actual)
차이는 다음과 같습니다.datatest.ValidationError
유효하지 않음, 편차, 누락 또는 추가 항목이 포함됩니다.
언급URL : https://stackoverflow.com/questions/32815640/how-to-get-the-difference-between-two-dictionaries-in-python
'source' 카테고리의 다른 글
ggplot2에서 매핑이 안정적인 범주형 변수에 색상을 할당하는 방법은 무엇입니까? (0) | 2023.07.16 |
---|---|
끈을 가지는 방법.누른 "전체 단어"만 바꾸기 (0) | 2023.07.16 |
디버깅을 위해 제너레이터 개체를 목록으로 변환 (0) | 2023.07.16 |
C++ 단일 줄 주석 뒤에 다중 줄 주석의 \변환이 나옵니다. (0) | 2023.07.16 |
ggplot2에서 그리드, 배경색 및 상단 및 오른쪽 테두리 제거 (0) | 2023.07.16 |