Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine two or more dictionaries with same keys

I have two dictionaries items and u_items

items = {"A": 1, "B": 2, "C": 3}

u_items = {"D": 4, "B": 4, "E": 8, "C": 4}

I want to update the items dictionary with u_items so I did this

items.update((k + '_1' if k in items else k, v) for k, v in u_items.items())

such that I can differentiate keys from both dictionaries

Output:

items = {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4}

but when i update the items dictionary with another dictionary, let's say n_items, it replaces the value of B_1 instead of making it B_1_1

n_items = {"C":7, "B":9}

items.update((k + '_1' if k in items else k, v) for k, v in n_items.items())

output:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 9, 'E': 8, 'C_1': 7}

But I want the output to be like this:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'B_1_1':9,'C_1_1':7}

or like this:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'B_2':9,'C_2':7}

How can I do it ?

like image 283
Rahul Sharma Avatar asked Oct 15 '22 15:10

Rahul Sharma


2 Answers

You can do this iteratively:

def combine(*args):
    result = {}
    for d in args:
        for key, value in d.items():
            key = str(key)
            while key in result:
                key += '_1'
            result[key] = value

    return result

print(combine(items, u_items, n_items))

Output:

{'A': 1,
 'B': 2,
 'C': 3,
 'D': 4,
 'B_1': 4,
 'E': 8,
 'C_1': 4,
 'C_1_1': 7,
 'B_1_1': 9}
like image 190
gmds Avatar answered Oct 18 '22 23:10

gmds


Although this seems a bit like an XY Problem, here's an ugly (and I'm pretty sure, inefficient) and also, not very general solution consisting of:

  • [Python 3.Docs]: Data Structures - Nested List Comprehensions
  • [Python 3.Docs]: Built-in Functions - max(iterable, *[, key, default])

that merges the dictionaries, by appending "_1" to an existing key (doing everything in one line), as you requested, although I'd recommend (since there are cases when the shortest is not necessarily the best):

  • Using a function (to avoid duplicating code (the expression))
  • Subclassing dict, and overriding its update method (a nicer variant of the previous one)
>>> items = {"A": 1, "B": 2, "C": 3}
>>> u_items = {"D": 4, "B": 4, "E": 8, "C": 4}
>>> n_items = {"C": 7, "B": 9}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in u_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in n_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_1_1': 7, 'B_1_1': 9}
>>>
>>>
>>> # Merging an additional dictionary
...
>>> v_items = {"C": 25}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in v_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_1_1': 7, 'B_1_1': 9, 'C_1_1_1': 25}
like image 38
CristiFati Avatar answered Oct 18 '22 23:10

CristiFati