Python: Check if one dictionary is a subset of another larger dictionary

前端 未结 16 643
轮回少年
轮回少年 2020-12-04 09:29

I\'m trying to write a custom filter method that takes an arbitrary number of kwargs and returns a list containing the elements of a database-like list that contain

相关标签:
16条回答
  • 2020-12-04 10:12

    Here's a general recursive solution for the problem given:

    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()
    

    NOTE: The original code would fail in certain cases, credits for the fixing goes to @olivier-melançon

    0 讨论(0)
  • 2020-12-04 10:15

    My function for the same purpose, doing this recursively:

    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
    

    In your example, dictMatch(d1, d2) should return True even if d2 has other stuff in it, plus it applies also to lower levels:

    d1 = {'a':'2', 'b':{3: 'iii'}}
    d2 = {'a':'2', 'b':{3: 'iii', 4: 'iv'},'c':'4'}
    
    dictMatch(d1, d2)   # True
    

    Notes: There could be even better solution which avoids the if type(pvalue) is dict clause and applies to even wider range of cases (like lists of hashes etc). Also recursion is not limited here so use at your own risk. ;)

    0 讨论(0)
  • 2020-12-04 10:15

    I know this question is old, but here is my solution for checking if one nested dictionary is a part of another nested dictionary. The solution is recursive.

    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
    
    0 讨论(0)
  • 2020-12-04 10:17

    Note for people that need this for unit testing: there's also an assertDictContainsSubset() method in Python's TestCase class.

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

    It's however deprecated in 3.2, not sure why, maybe there's a replacement for it.

    0 讨论(0)
提交回复
热议问题