-1

Let's say we have these two dictionaries:

a = {"A": "MyText", "B": {"Sub": "Hello", "NextSub": "Bye"}}
b = {"B": {"NextSub": 55}}

How to merge them together so that I get this result (such that it will work with every type of dictionary)?

ab = {"A": "MyText", "B": {"Sub": "Hello", "NextSub": 55}}

a.update(b) just replaces "B".

I want to merge some dicts because I need to handle with them all. So it's faster if I handle with one merged dict which contains the latest information of all dicts instead of handling with more dicts in a for-loop which would be slower.

Thank you!

Frostie
  • 77
  • 2
  • 10
  • There is a lot of discussion [here](https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge). I won't vote to close because you asked for a "clean" way. – wim Feb 06 '18 at 19:44
  • Thats no reason to vote that down. And we have a clean solution down here^^ – Frostie Feb 06 '18 at 19:56
  • 1
    If you think that's clean, you have lower standards than you should... :) p.s. I didn't downvote you – wim Feb 06 '18 at 20:08
  • Haha^^ you got me – Frostie Feb 06 '18 at 20:09

1 Answers1

1

For a generic solution, you can use recursion:

l = [[{"A": "MyText", "B": {"Sub": "Hello", "NextSub": "Bye"}},{"B": {"NextSub": 55}}], [{"a": {"a": {"a": 2, "b": "bye"}}}, {"a": {"a": {"a": "Hello"}}}]]
def update(a, b):
   if len(a) == len(b):
      return {c:d if not isinstance(d, dict) else {**d, **h} if c == e and all(not isinstance(i, dict) for _, i in d.items()) else update(d, h) for [c, d], [e, h] in zip(a.items(), b.items())}
   return {c:d if not isinstance(d, dict) else {**d, **b[c]} if all(not isinstance(i, dict) for _, i in d.items()) else update(d, b) for c, d in a.items()}

results = [update(*i) for i in l]

Output:

[{'A': 'MyText', 'B': {'Sub': 'Hello', 'NextSub': 55}}, {'a': {'a': {'a': 'Hello', 'b': 'bye'}}}]
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • @Frostie glad to help! – Ajax1234 Feb 06 '18 at 19:52
  • @Frostie this solution supports `a` with n-levels of nested dictionaries, however, it would only replace a key in `a` with the highest level equivalent in `b`. If you are looking for a solution that is more complex in terms of a substitution with a nested `b`, can you explain your criteria? – Ajax1234 Feb 06 '18 at 20:24
  • I want to merge some dicts because I need to handle with them all. So it's faster if I handle with one merged dict which contains the latest information of all dicts instead of handling with more dicts in a for-loop which would be slower. And there can be subdicts of subdicts of subdicts of subdicts... I see that you call the function again in the function itself, but in subdicts of subdicts, it replaces the whole subdict: `{"a": {"a": {"a": 2, "b": "bye"}}} + {"a": {"a": {"a": "Hello"}}} becomes {"a": {"a": {"a": "Hello"}}} instead of {"a": {"a": {"a": "Hello", "b": "bye"}}}` – Frostie Feb 06 '18 at 20:30
  • @Frostie what is your desired output from `{"a": {"a": {"a": 2, "b": "bye"}}} + {"a": {"a": {"a": "Hello"}}}`? Also, it is guaranteed that `a` will be the same depth as `b`? – Ajax1234 Feb 06 '18 at 20:33
  • Yes, a will have the same depth. It has to be: `{"a": {"a": {"a": "Hello", "b": "bye"}}}` – Frostie Feb 06 '18 at 20:35
  • @Frostie please see my recent edit. I encapsulated all the dictionaries you have mentioned into a list of lists both for testing and demonstration purposes. – Ajax1234 Feb 06 '18 at 20:56