[python] Python : 한 사전이 다른 더 큰 사전의 하위 집합인지 확인

임의의 수의 kwargs 를 사용하고 해당 kwargs 를 포함하는 데이터베이스와 같은 목록의 요소를 포함하는 목록을 반환 하는 사용자 지정 필터 메서드를 작성하려고합니다 .

예를 들어, d1 = {'a':'2', 'b':'3'}and d2= 같은 것을 가정 하십시오. d1 == d2True가됩니다. 그러나 d2= 같은 것 + 다른 것들이 있다고 가정 하십시오. 내 방법 은 d2의 d1 인지 알 수 있어야 하지만 파이썬은 사전으로 그렇게 할 수 없습니다.

문맥:

Word 클래스가 있고 각 개체에는 word,, definition등의 속성이 있습니다 part_of_speech. 이 단어의 기본 목록에서 필터 메서드를 호출 할 수 있기를 원합니다 Word.objects.filter(word='jump', part_of_speech='verb-intransitive'). 이 키와 값을 동시에 관리하는 방법을 알 수 없습니다. 그러나 이것은 다른 사람들을 위해이 컨텍스트 밖에서 더 큰 기능을 가질 수 있습니다.



답변

항목 쌍으로 변환하고 격리를 확인하십시오.

all(item in superset.items() for item in subset.items())

최적화는 독자를위한 연습으로 남겨집니다.


답변

Python 3에서는을 사용 dict.items()하여 dict 항목의 세트와 같은보기를 얻을 수 있습니다 . 그런 다음 <=연산자를 사용하여 한보기가 다른보기의 “하위 집합”인지 테스트 할 수 있습니다 .

d1.items() <= d2.items()

Python 2.7에서를 사용 dict.viewitems()하여 동일한 작업을 수행합니다.

d1.viewitems() <= d2.viewitems()

Python 2.6 이하에서는 다음을 사용하는 것과 같은 다른 솔루션이 필요합니다 all().

all(key in d2 and d2[key] == d1[key] for key in d1)


답변

단위 테스트를 위해 이것을 필요로하는 사람들을위한 참고 : assertDictContainsSubset()Python의 TestCase클래스 에도 메서드가 있습니다.

http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset

그러나 3.2에서는 더 이상 사용되지 않으며 이유가 확실하지 않으며 대체가있을 수 있습니다.


답변

키 및 값 확인 사용 :
set(d1.items()).issubset(set(d2.items()))

키만 확인해야하는 경우 :
set(d1).issubset(set(d2))


답변

완전성을 위해 다음을 수행 할 수도 있습니다.

def is_subdict(small, big):
    return dict(big, **small) == big

그러나 나는 속도 (또는 속도 부족) 또는 가독성 (또는 부족)과 관련하여 어떠한 주장도하지 않습니다.


답변

>>> 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 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를 반환해야하며 더 낮은 수준에도 적용됩니다.

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절 을 피하고 더 넓은 범위의 경우 (해시 목록 등)에 적용 하는 더 나은 솔루션이있을 수 있습니다 . 또한 재귀는 여기에 제한되지 않으므로 자신의 책임하에 사용하십시오. 😉