Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to map a dict value to another dict

I'm wondering what is the best way to merge 2 dicts into one dict as follows: dict1 = {k1: v1, k2: v2, ...}and dict2 = {v1: w1, v2: w2, ...}into result = {k1: w1, k2: w2, ...}

I already have a solution using dict comprehension:

result = {
   k: dict2[v]
   for k, v in dict1.items()
}

But I don't think this is the most elegant way to do it. Can you please help me ?

like image 275
Marouan Sami Avatar asked Jan 27 '23 19:01

Marouan Sami


2 Answers

As an alternative/extension, to @jpp's answer, you could also use reduce/functools.reduce to get a slightly more condensed form of the chainer function:

from functools import reduce
def chainer(first, *others):
    return {k: reduce(lambda x, d: d[x], others, v) for k, v in first.items()}

Which of those is better is mainly a matter of taste; usage and results are the same.

For just two dictionaries, your dictionary comprehension is IMHO as good and elegant as it gets. You might want to use get or add a condition in case a key is not present in the second dict, though.

>>> dict1 = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
>>> dict2 = {'v1': 'w1', 'v2': 'w2'}
>>> {k: dict2.get(v, 'undefined') for k, v in dict1.items()}
{'k1': 'w1', 'k2': 'w2', 'k3': 'undefined'}
>>> {k: dict2[v] for k, v in dict1.items() if v in dict2}
{'k1': 'w1', 'k2': 'w2'}

Adding a safeguard like this into the chainer is a bit more involved, in particular for this variant using reduce (and might not be necessary at all).

like image 187
tobias_k Avatar answered Jan 31 '23 08:01

tobias_k


For the two-dictionary case, your dictionary comprehension is fine. This assumes you can guarantee your values in dict1 are keys in dict2.

Considering how you can extend this to arbitrary dictionary inputs, you can use a for loop:

dict1 = {'k1': 'v1', 'k2': 'v2'}
dict2 = {'v1': 'w1', 'v2': 'w2'}
dict3 = {'w1': 'x1', 'w2': 'x2'}

def chainer(first, *others):
    res = first.copy()  # make a copy to avoid overwriting dict1
    for k, v in res.items():
        for dct in others:
            v = dct[v]
        res[k] = v
    return res

res = chainer(dict1, dict2, dict3)
# {'k1': 'x1', 'k2': 'x2'}
like image 44
jpp Avatar answered Jan 31 '23 09:01

jpp