한 사전이 다른 더 큰 사전의 하위 집합인지 확인하는 방법은 무엇입니까?
임의의 수의 kwarg를 가져다가 해당 kwarg를 포함하는 데이터베이스와 유사한 목록의 요소를 포함하는 목록을 반환하는 사용자 정의 필터 방법을 작성하려고 합니다.
를 들어, 를들어예,어들▁suppose▁for,d1 = {'a':'2', 'b':'3'}
그리고.d2
같은 것 d1 == d2
결과가 True가 됩니다.하지만 예를 들어d2
같은 것에 다른 많은 것들을 더한 것들.내 방법은 d2의 d1을 구별할 수 있어야 하지만, 파이썬은 사전으로 그렇게 할 수 없습니다.
컨텍스트:
저는 클래스가 , 는 워드 클가있각고개다체음같가속집다니은성을과는래스▁wordties▁like와 같은 속성을 가지고 .word
,definition
,part_of_speech
등등.나는 이 단어들의 주요 목록에 있는 필터 메소드를 부를 수 있기를 원합니다.Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
이 키와 값을 동시에 관리하는 방법을 모르겠습니다.하지만 이것은 다른 사람들을 위해 이 맥락 밖에서 더 큰 기능을 가질 수 있습니다.
3에서는 3을 사용할 수 .dict.items()
딕트 항목을 세트처럼 표시합니다.그러면 다음을 사용할 수 있습니다.<=
뷰가 뷰의 인지 테스트하는 : " 한 부 " 분 " 할 " 산 인 " 자 " 연 " subset " 트 " 스 " 지 " 테 " 의 "
d1.items() <= d2.items()
2에서는 Python 2.7을 합니다.에서는dict.viewitems()
동일한 작업 수행:
d1.viewitems() <= d2.viewitems()
2에서는 Python 2.6을 사용하는 등 합니다.all()
:
all(key in d2 and d2[key] == d1[key] for key in d1)
항목 쌍으로 변환하고 격납 여부를 확인합니다.
all(item in superset.items() for item in subset.items())
최적화는 독자를 위한 연습으로 남겨집니다.
장치 테스트를 위해 이것이 필요한 사람들을 위한 참고 사항: 또한 있습니다.assertDictContainsSubset()
파이메드에 TestCase
학생들
그러나 3.2에서는 더 이상 사용되지 않습니다. 그 이유는 확실하지 않습니다. 대신 사용할 수도 있습니다.
완전성을 위해 다음 작업도 수행할 수 있습니다.
def is_subdict(small, big):
return dict(big, **small) == big
그러나 속도(또는 속도의 부족) 또는 가독성(또는 부족)과 관련하여 어떠한 주장도 하지 않습니다.
업데이트: Boris의 코멘트에서 지적했듯이, 이 트릭은 당신의 작은 딕트에 문자열이 아닌 키가 있고 당신이 Python >= 3을 사용하고 있다면 작동하지 않습니다(다시 말해, 임의로 입력한 키 앞에서는, 레거시 Python 2.x에서만 작동합니다).
그러나 Python 3.9 이상을 사용하는 경우 문자열이 아닌 입력된 키 모두에서 작동할 수 있을 뿐만 아니라 더 깔끔한 구문을 얻을 수 있습니다.
코드에 이미 두 개의 사전이 변수로 포함되어 있는 경우 이 인라인을 확인하는 것이 매우 간단합니다.
if big | small == big:
# do something
그렇지 않은 경우 또는 위와 같이 재사용 가능한 기능을 선호하는 경우 다음을 사용할 수 있습니다.
def is_subdict(small, big):
return big | small == big
작동 원리는 첫 번째 기능과 동일하지만, 이번에는 딕트를 지원하도록 확장된 조합 운영자를 사용하는 것과 관련이 있습니다.
키 및 값을 확인하려면 다음을 사용합니다.set(d1.items()).issubset(set(d2.items()))
키만확하는경우야인:set(d1).issubset(set(d2))
>>> d1 = {'a':'2', 'b':'3'}
>>> d2 = {'a':'2', 'b':'3','c':'4'}
>>> all((k in d2 and d2[k]==v) for k,v in d1.iteritems())
True
컨텍스트:
>>> d1 = {'a':'2', 'b':'3'}
>>> d2 = {'a':'2', 'b':'3','c':'4'}
>>> list(d1.iteritems())
[('a', '2'), ('b', '3')]
>>> [(k,v) for k,v in d1.iteritems()]
[('a', '2'), ('b', '3')]
>>> k,v = ('a','2')
>>> k
'a'
>>> v
'2'
>>> k in d2
True
>>> d2[k]
'2'
>>> k in d2 and d2[k]==v
True
>>> [(k in d2 and d2[k]==v) for k,v in d1.iteritems()]
[True, True]
>>> ((k in d2 and d2[k]==v) for k,v in d1.iteritems())
<generator object <genexpr> at 0x02A9D2B0>
>>> ((k in d2 and d2[k]==v) for k,v in d1.iteritems()).next()
True
>>> all((k in d2 and d2[k]==v) for k,v in d1.iteritems())
True
>>>
다음은 사전에 포함된 목록과 집합으로 올바르게 재귀하는 솔루션입니다.딕트 등이 포함된 목록에도 사용할 수 있습니다.
def is_subset(subset, superset):
if isinstance(subset, dict):
return all(key in superset and is_subset(val, superset[key]) for key, val in subset.items())
if isinstance(subset, list) or isinstance(subset, set):
return all(any(is_subset(subitem, superitem) for superitem in superset) for subitem in subset)
# assume that subset is a plain value if none of the above match
return subset == superset
python 3.10을 사용할 때 python의 새로운 match 문을 사용하여 유형 검사를 수행할 수 있습니다.
def is_subset(subset, superset):
match subset:
case dict(_): return all(key in superset and is_subset(val, superset[key]) for key, val in subset.items())
case list(_) | set(_): return all(any(is_subset(subitem, superitem) for superitem in superset) for subitem in subset)
# assume that subset is a plain value if none of the above match
case _: return subset == superset
Python 3.9에서는 다음과 같이 사용합니다.
def dict_contains_dict(small: dict, big: dict):
return (big | small) == big
동일한 목적을 위한 내 기능, 재귀적으로 수행:
def dictMatch(patn, real):
"""does real dict match pattern?"""
try:
for pkey, pvalue in patn.iteritems():
if type(pvalue) is dict:
result = dictMatch(pvalue, real[pkey])
assert result
else:
assert real[pkey] == pvalue
result = True
except (AssertionError, KeyError):
result = False
return result
예에서, 를들어예는,dictMatch(d1, d2)
를 반환해야 . 됩니다.d2 다 른 항 목 를 포 있 에 True 반 야 하 수 위 준 에 도 적 됩 용 니 다 하 며 해 환 라 더 도 어 이 되 함 됩 ▁should 니 다 ▁true
d1 = {'a':'2', 'b':{3: 'iii'}}
d2 = {'a':'2', 'b':{3: 'iii', 4: 'iv'},'c':'4'}
dictMatch(d1, d2) # True
참고: 더 나은 솔루션이 있을 수 있습니다.if type(pvalue) is dict
더 광범위한 사례(해시 목록 등)에 적용됩니다.또한 재귀는 여기에 제한되지 않으므로 위험을 감수하고 사용하십시오.;)
괜찮으시다면 사용하세요.pydash
이 있습니다.is_match
거기서 정확히 다음과 같은 일을 합니다.
import pydash
a = {1:2, 3:4, 5:{6:7}}
b = {3:4.0, 5:{6:8}}
c = {3:4.0, 5:{6:7}}
pydash.predicates.is_match(a, b) # False
pydash.predicates.is_match(a, c) # True
겉보기에는 간단해 보이는 이 문제로 인해 100% 신뢰할 수 있는 솔루션을 찾기 위해 몇 시간의 연구 시간이 소요되므로 이 답변에서 발견한 내용을 문서화했습니다.
"파이토닉 아군"입니다.
small_dict <= big_dict
가장 직관적인 방법이겠지만, 작동하지 않는 것이 유감입니다.{'a': 1} < {'a': 1, 'b': 2}
겉보기에는 Python 2에서 작동하지만 공식 문서에서 명시적으로 호출하기 때문에 신뢰할 수 없습니다.이동 이 절에서 "평등 이외의 결과는 일관되게 해결되지만 정의되지는 않습니다."를 검색합니다.말할 것도 없이 Python 3에서 2개의 딕트를 비교하면 TypeError 예외가 발생합니다.은 두번로직인것은적입니다.
small.viewitems() <= big.viewitems()
2 및 Python 2.7 용small.items() <= big.items()
Python 3용.하지만 한 가지 주의할 점이 있습니다: 그것은 잠재적으로 버그가 있습니다.당신의 프로그램이 잠재적으로 파이썬 <=2.6에서 사용될 수 있다면, 그것은d1.items() <= d2.items()
실제로 특별한 순서 없이 튜플의 두 목록을 비교하고 있기 때문에 최종 결과는 신뢰할 수 없을 것이고 당신의 프로그램에서 끔찍한 버그가 될 것입니다.파이썬<=2.6을 위한 다른 구현체를 작성하고 싶지 않지만, 제 코드가 알려진 버그와 함께 제공된다는 것이 여전히 불편합니다(지원되지 않는 플랫폼에 있더라도).그래서 저는 이 접근법을 포기합니다.저는 @blubberdiblub의 대답에 안주합니다(신용은 그에게 있습니다).
def is_subdict(small, big): return dict(big, **small) == big
이 대답은 다음에 의존한다는 것을 지적할 가치가 있습니다.
==
딕트 간의 동작은 공식 문서에 명확하게 정의되어 있으므로 모든 파이썬 버전에서 작동해야 합니다.이동 검색:
다음은 문제에 대한 일반적인 재귀 솔루션입니다.
import traceback
import unittest
def is_subset(superset, subset):
for key, value in subset.items():
if key not in superset:
return False
if isinstance(value, dict):
if not is_subset(superset[key], value):
return False
elif isinstance(value, str):
if value not in superset[key]:
return False
elif isinstance(value, list):
if not set(value) <= set(superset[key]):
return False
elif isinstance(value, set):
if not value <= superset[key]:
return False
else:
if not value == superset[key]:
return False
return True
class Foo(unittest.TestCase):
def setUp(self):
self.dct = {
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': {1, 2, 3, 4, 5},
'f': {
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': {1, 2, 3, 4, 5},
'g': False,
'h': None
},
'g': False,
'h': None,
'question': 'mcve',
'metadata': {}
}
def tearDown(self):
pass
def check_true(self, superset, subset):
return self.assertEqual(is_subset(superset, subset), True)
def check_false(self, superset, subset):
return self.assertEqual(is_subset(superset, subset), False)
def test_simple_cases(self):
self.check_true(self.dct, {'a': 'hello world'})
self.check_true(self.dct, {'b': 12345})
self.check_true(self.dct, {'c': 1.2345})
self.check_true(self.dct, {'d': [1, 2, 3, 4, 5]})
self.check_true(self.dct, {'e': {1, 2, 3, 4, 5}})
self.check_true(self.dct, {'f': {
'a': 'hello world',
'b': 12345,
'c': 1.2345,
'd': [1, 2, 3, 4, 5],
'e': {1, 2, 3, 4, 5},
}})
self.check_true(self.dct, {'g': False})
self.check_true(self.dct, {'h': None})
def test_tricky_cases(self):
self.check_true(self.dct, {'a': 'hello'})
self.check_true(self.dct, {'d': [1, 2, 3]})
self.check_true(self.dct, {'e': {3, 4}})
self.check_true(self.dct, {'f': {
'a': 'hello world',
'h': None
}})
self.check_false(
self.dct, {'question': 'mcve', 'metadata': {'author': 'BPL'}})
self.check_true(
self.dct, {'question': 'mcve', 'metadata': {}})
self.check_false(
self.dct, {'question1': 'mcve', 'metadata': {}})
if __name__ == "__main__":
unittest.main()
참고: 경우에 따라 원래 코드가 실패할 수 있습니다. 수정에 대한 크레딧은 @olivier-melancon에게 전달됩니다.
이 질문이 오래된 질문인 것은 알지만, 중첩된 사전이 다른 중첩된 사전의 일부인지 확인하기 위한 해결책이 있습니다.솔루션은 재귀적입니다.
def compare_dicts(a, b):
for key, value in a.items():
if key in b:
if isinstance(a[key], dict):
if not compare_dicts(a[key], b[key]):
return False
elif value != b[key]:
return False
else:
return False
return True
이를 위한 다른 방법:
>>> d1 = {'a':'2', 'b':'3'}
>>> d2 = {'a':'2', 'b':'3','c':'4'}
>>> d3 = {'a':'1'}
>>> set(d1.items()).issubset(d2.items())
True
>>> set(d3.items()).issubset(d2.items())
False
부분 비교 및 nice diff를 제공하는 이 래퍼 개체를 사용합니다.
class DictMatch(dict):
""" Partial match of a dictionary to another one """
def __eq__(self, other: dict):
assert isinstance(other, dict)
return all(other[name] == value for name, value in self.items())
actual_name = {'praenomen': 'Gaius', 'nomen': 'Julius', 'cognomen': 'Caesar'}
expected_name = DictMatch({'praenomen': 'Gaius'}) # partial match
assert expected_name == actual_name # True
딕트 내에 다른 딕트 배열이 있는 경우 대부분의 답변이 작동하지 않습니다. 이에 대한 해결책은 다음과 같습니다.
def d_eq(d, d1):
if not isinstance(d, (dict, list)):
return d == d1
if isinstance(d, list):
return all(d_eq(a, b) for a, b in zip(d, d1))
return all(d.get(i) == d1[i] or d_eq(d.get(i), d1[i]) for i in d1)
def is_sub(d, d1):
if isinstance(d, list):
return any(is_sub(i, d1) for i in d)
return d_eq(d, d1) or (isinstance(d, dict) and any(is_sub(b, d1) for b in d.values()))
print(is_sub(dct_1, dict_2))
taked from dict가 다른 복잡한 dict의 하위 집합인지 확인하는 방법
이 함수는 해시할 수 없는 값에 대해 작동합니다.저는 또한 그것이 분명하고 읽기 쉽다고 생각합니다.
def isSubDict(subDict,dictionary):
for key in subDict.keys():
if (not key in dictionary) or (not subDict[key] == dictionary[key]):
return False
return True
In [126]: isSubDict({1:2},{3:4})
Out[126]: False
In [127]: isSubDict({1:2},{1:2,3:4})
Out[127]: True
In [128]: isSubDict({1:{2:3}},{1:{2:3},3:4})
Out[128]: True
In [129]: isSubDict({1:{2:3}},{1:{2:4},3:4})
Out[129]: False
중첩된 사전에 대해 작동하는 짧은 재귀 구현:
def compare_dicts(a,b):
if not a: return True
if isinstance(a, dict):
key, val = a.popitem()
return isinstance(b, dict) and key in b and compare_dicts(val, b.pop(key)) and compare_dicts(a, b)
return a == b
이렇게 하면 a 및 bdt가 소모됩니다.다른 답변처럼 부분적으로 반복적인 해결책에 의존하지 않고 그것을 피할 수 있는 좋은 방법을 아는 사람이 있다면 저에게 말해주십시오.저는 딕트를 키를 기반으로 머리와 꼬리로 나누는 방법이 필요합니다.
이 코드는 프로그래밍 연습으로 더 유용하며, 재귀와 반복을 혼합하는 다른 솔루션보다 훨씬 느릴 수 있습니다.@호두까기 인형의 솔루션은 중첩된 사전에 적합합니다.
언급URL : https://stackoverflow.com/questions/9323749/how-to-check-if-one-dictionary-is-a-subset-of-another-larger-dictionary
'programing' 카테고리의 다른 글
오브젝트 키를 기반으로 TypeScript에서 동적으로 열거형을 생성하는 방법이 있습니까? (0) | 2023.06.15 |
---|---|
IEnumberable에 Count 메서드가 없습니다. (0) | 2023.06.15 |
.contiguous()는 PyTorch에서 무엇을 합니까? (0) | 2023.06.15 |
ASP.NET Web API - Startup.cs 이 존재하지 않습니다. (0) | 2023.06.10 |
Gitdiff 커밋 범위에서 이중 점 ""과 삼중 점 "..."의 차이점은 무엇입니까? (0) | 2023.06.10 |