2

I need to verify if another dict is a subset of another dict, there is a trick that in these dicts there are array of dict's.

superset:

   dct_1 = {
        'x': 'x',
        'y': [
            {
                't': '123',
                'a': 'a'
            }
        ]
    }

subset:

dict_2 = {
        'x': 'x',
        'y': [
            {
                't': '123'
            }
        ]
    }

from Recursive function to check dictionary is a subset of another dictionary answer I get this error:

TypeError: unhashable type: 'dict'

My code:

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 Test(unittest.TestCase):

    def setUp(self):
        self.dct = {
            'x': 'x',
            'y': [
                {
                    't': '123',
                    'a': 'a'
                }
            ]
        }

    def check_is_subset_true(self, superset, subset):
        return self.assertEqual(is_subset(superset, subset), True)

    def test_is_true(self):
        self.check_is_subset_true(self.dct, {
            'x': 'x',
            'y': [
                {
                    't': '123'
                }
            ]
        })
Marius
  • 151
  • 5

2 Answers2

1

Here's a way of doing it, is it enough for you use case ?

def is_subset(superset, subset):
    if type(superset) != type(subset):
        return False
    
    if isinstance(subset, dict):
        for key, value in subset.items():
            try:
                if not is_subset(superset[key], value):
                    return False
            except KeyError:
                return False
                
    elif isinstance(subset, list):
        for sub_e, super_e in zip(subset, superset):
            if not is_subset(super_e, sub_e):
                return False

    else:
        if superset != subset:
            return False
        
    return True
        

is_subset(dict_1, dict_2)
# True
RobinFrcd
  • 4,439
  • 4
  • 25
  • 49
1

You can traverse the complex dictionary and at each stage, attempt to match the current dictionary with the potential subset dictionary:

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

Output:

True
Ajax1234
  • 69,937
  • 8
  • 61
  • 102