0

I have a dictionary of dictionary as follows:

lst1 = {1: {"a": "x","b": "y"}, 2: {"b": "y", "c": "z"}}

I want to make a flat dict out of it. Any duplicate keys should be removed, so that only keys unique to one of the nested dicts are present in the flattened dict. The dict above should become:

{"a": "x", "c": "z"}

the simple code would be:

for key, value in lst1.iteritems():
   for key1, value1  in value.iteritems():
      if key1 <> "b":
         lst2[key1]=value1 

I tried some of previous answers here, here and here but couldn't get it to work right.

The below code returns error: the value is not defined

lst2 = {key1: value1 for key1, value1 in value for key, value in lst1.items()}

This one:

 lst2 = dict((key1, value1) for key1, value1 in (value for key, value in lst1.items()))

returns:

 {'a': 'b', 'c': 'b'}

How can I flatten the structure correctly as I've described?

Community
  • 1
  • 1
msc87
  • 943
  • 3
  • 17
  • 39

1 Answers1

1

It may not be possible with a single comprehension, since you need to track which keys have already been added to the flattened structure in order to remove them on duplicate. A solution that builds the flattened structure in a for loop is still straightforward. Add items from the sub-dicts to the output, or delete if the key is found again.

data = {1: {'a': 'x', 'b': 'y'}, 2: {'b': 'y', 'c': 'z'}}
out = {}

for sub in data.values():
     for key, value in sub.items():
         if key in out:
             del out[key]
         else:
             out[key] = value

print(out)  # {'a': 'x', 'c': 'z'}

You can also do it using two comprehensions and a Counter. First track how many times each sub-key appears, then only flatten the keys with a single occurrence.

from collections import Counter

data = {1: {'a': 'x', 'b': 'y'}, 2: {'b': 'y', 'c': 'z'}}

c = Counter(key for sub in data.values() for key in sub)
out = {key: value for sub in data.values() for key, value in sub.items() if c[key] == 1}

print(out)  # {'a': 'x', 'c': 'z'}
davidism
  • 121,510
  • 29
  • 395
  • 339