Home > Net >  Python: Most efficient way to combine complex dictionaries
Python: Most efficient way to combine complex dictionaries

Time:12-15

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