Python: Most elegant way to merge two dictionaries with the same key

142 Views Asked by At

I am working on genome-scale models and trying to create a minimal medium that suits two optimal flux conditions. I get two dictionaries with the required medium components looking like this:

EX_C00001_ext_b     1.132993
EX_C00011_ext_b     1.359592
EX_E1_ext_b        16.000000

EX_C00034_ext_b      0.000088
EX_C00244_ext_b      0.259407
EX_C00182N_cyt_b     0.006079
EX_C00009_ext_b      0.020942
EX_C01330_ext_b      0.000110
EX_C00080_ext_b      0.258331
EX_C00001_ext_b      0.780699
EX_C14819_ext_b      0.000197
EX_C00059_ext_b      0.005162
EX_C00011_ext_b      1.198398
EX_C14818_ext_b      0.000217
EX_C00305_ext_b      0.000802
EX_C00038_ext_b      0.000088
EX_C00070_ext_b      0.000088
EX_C06232_ext_b      0.000088
EX_C00076_ext_b      0.000131
EX_C00238_ext_b      0.004925
EX_E1_ext_b         16.000000
EX_C00175_ext_b      0.000094

I want to merge both dictionaries to selected the highest value for each metabolite in the most elegant way and it should be usable regardless of the dictionary size.

It should give me the following result:

EX_C00034_ext_b      0.000088
EX_C00244_ext_b      0.259407
EX_C00182N_cyt_b     0.006079
EX_C00009_ext_b      0.020942
EX_C01330_ext_b      0.000110
EX_C00080_ext_b      0.258331
EX_C00001_ext_b      1.132993
EX_C14819_ext_b      0.000197
EX_C00059_ext_b      0.005162
EX_C00011_ext_b      1.359592
EX_C14818_ext_b      0.000217
EX_C00305_ext_b      0.000802
EX_C00038_ext_b      0.000088
EX_C00070_ext_b      0.000088
EX_C06232_ext_b      0.000088
EX_C00076_ext_b      0.000131
EX_C00238_ext_b      0.004925
EX_E1_ext_b         16.000000
EX_C00175_ext_b      0.000094

Here are the example dicts for you to use.

{'EX_C00034_ext_b': 8.757888959017035e-05, 'EX_C00244_ext_b': 0.2594073529471562, 'EX_C00182N_cyt_b': 0.006078784247428623, 'EX_C00009_ext_b': 0.02094224214212716, 'EX_C01330_ext_b': 0.00010954587179767827, 'EX_C00080_ext_b': 0.2583314448433369, 'EX_C00001_ext_b': 0.7806992563484072, 'EX_C14819_ext_b': 0.00019712476138777617, 'EX_C00059_ext_b': 0.005162038491279668, 'EX_C00011_ext_b': 1.1983981620820985, 'EX_C14818_ext_b': 0.00021724189246195394, 'EX_C00305_ext_b': 0.0008020492051022175, 'EX_C00038_ext_b': 8.757888959017035e-05, 'EX_C00070_ext_b': 8.757888959017036e-05, 'EX_C06232_ext_b': 8.757888959017035e-05, 'EX_C00076_ext_b': 0.00013122381476546977, 'EX_C00238_ext_b': 0.0049252286422986884, 'EX_E1_ext_b': 16.000000000000245, 'EX_C00175_ext_b': 9.42845999482296e-05}

{'EX_C00001_ext_b': 1.1329932376320115, 'EX_C00011_ext_b': 1.3595918851584152, 'EX_E1_ext_b': 16.000000000000387}

Please note that I don't know in which of the dictionarys the higher values are.

EDIT

As you can see from my example even though both dictionary's contain the same keys, not all keys are in both dictionary's. So I can't loop through the keys since I don't know if I skip one of the keys. I guess you could first create a set out of all keys from all the dictionary's I need to merge but I am not sure if it is a good way.

Yes only the highest value should be saved.

EDIT 2

Unfortunatly after updating the medium this way I get an error

TypeError: in method 'Reaction_setReversible', argument 2 of type 'bool'

when I try to write the model with the updated medium to an xml file.

**Last EDIT **

If anyone encounters the same problem, you just need to specify that the values are floats. Everything worked afterwards.

3

There are 3 best solutions below

2
On BEST ANSWER

You can use the following dictcomp:

dct1 = {'A': 0, 'B': 9, 'C': 9}
dct2 = {'A': 9, 'B': 0}

{key: max(dct1.get(key, 0), dct2.get(key, 0)) for key in dct1.keys() | dct2.keys()}
# {'A': 9, 'C': 9, 'B': 9}
2
On

You can use one-liner, provided by Mykola Zlotko, it is good and very pythonic way. Or you can use longer version, something like this:

for key, value in dict1.keys():
    if key in dict2:
         dict2[key] = max(dict1[key], dict2[key])
    else:
         dict2[key] = value
0
On

You can iterate over all keys instead of to create temporary a set object keeping keys of the dictionaries, which makes sense if the dictionaries are large.

from itertools import *

def f(d1, d2):
    keys = chain(d1.keys(), d2.keys())
    return {k: max(d1.get(k, 0), d2.get(k, 0)) for k in keys}

a = {0: 888, 1: 10, 2: 20, 3: 30, 4: 40}
b = {1: 100, 2: 2, 5: 50}

print(f2(a, b))
print(f2(b, a))

# OUTPUT:
{0: 888, 1: 100, 2: 20, 3: 30, 4: 40, 5: 50}
{1: 100, 2: 20, 5: 50, 0: 888, 3: 30, 4: 40}