Let's say I have two dicts consisting of multi-leveled sets:
houses:
- house4:
- level1:
- unitA
- unitB
- level8:
- unitG
- house6:
- level5:
- unitK
and
houses:
- house6:
- level4:
- unitT
- level5:
- unitK
- house3:
- level8:
- unitG
What is the most efficient way to combine them without duplicates?
I can write a three level loop and generate a new dict by recombining each subset with set.union but that kind of doesn't look nice.
CodePudding user response:
Assuming the units are sets, you can do it with 2 for-loops.
Iterate over b
and check if a house in it exists in a
, if not just add it to a
. If it is, then iterate over the levels in that house and check if a level in it exists in the same house in a
. If there is, then add these new units to the existing level in a
, if not add this level to the same house in a
:
for house, levels in b.items():
if house in a:
for level, units in levels.items():
if level in a[house]:
a[house][level].update(units)
else:
a[house][level] = units
else:
a[house] = levels
The same can be constructed using dict.setdefault
as well:
for house, levels in b.items():
a.setdefault(house, dict())
for level, units in levels.items():
a[house].setdefault(level, set()).update(units)
print(a)
Output:
{'house4': {'level1': {'unitA', 'unitB'}, 'level8': ['unitG']},
'house6': {'level6': {'unitK'}, 'level4': {'unitT'}, 'level5': {'unitK'}},
'house3': {'level8': {'unitG'}}}
CodePudding user response:
a ={"house4": {
"level1": ["unitA", "unitB"],
"level8": ["unitG"],
},
"house6": {
"level6": ["unitK"]
}
}
b = {"house6": {
"level4": ["unitT"],
"level5": ["unitK"]
},
"house3": {
"level8": ["unitG"]
}
}
a.update(b)
keys in "a" are replaced by "b" i.e. "a" once updated will have the value of "house 6" from dictionary "b". If you need to resolve duplicates at a lower level in your dictionary, make sure to post a question that demos exactly what you need--it's unclear.
CodePudding user response:
Assuming that your last level of these dictionaries are sets of strings, you could use nested loops:
for k1,v1 in b.items(): # e.g. 'houses': {...
d1 = a.setdefault(k1,dict())
for k2,v2 in v1.items(): # e.g. 'house6': {...
d2 = d1.setdefault(k2,dict())
for k3,v3 in v2.items(): # e.g. 'level4': {'unitT'}
d2.setdefault(k3,list()).update(v3)
Note that the sub-dictionaries added to a
are new instances (not references to the ones in b
. So if the content of the b
structure is changed afterward, you won't get undesirable side effect in the a
structure.
If the number of levels in the dictionaries is unknown, you can define a recursive function that does the same thing for any number of levels:
def merge(a,b):
if isinstance(a,dict):
for k,v in b.items(): merge(a.setdefault(k,type(v)()),v)
elif isinstance(a,set): a.update(b)
elif isinstance(a,list): a.extend(b)