7
\$\begingroup\$

I have two dictionaries and a merged dictionary:

dict1 = {-3: 0.3, -2: 0.1, 1: 0.8}
dict2 = {0: 0.3, 1: 0.5, -1: 0.7}
dict_merged = {}

I have code that basically merges the two together by adding keys together and multiplying values: e.g.

for k1, v1 in dict1.items():
   for k2, v2 in dict2.items():
      new_key = k1 + k2
      if new_key in dict_merged:
          dict_merged[new_key] += v1 * v2
      else:
          dict_merged[new_key] = v1 * v2

Is there a faster way to do this, it feels like there should but dict comprehension doesn't seem helpful here. In the above example, we are going to get several contributes to the key "-3" for example.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Be advised that in Python<3.7 the order of the keys are not guaranteed. Your code might work in your PC, but in someone else's might break horribly. \$\endgroup\$
    – pepoluan
    Mar 11 '20 at 1:59
  • 2
    \$\begingroup\$ @pepoluan strange advice, since the code here doesn't require the dictionaries to be sorted. \$\endgroup\$
    – Peilonrayz
    Mar 11 '20 at 11:46
  • \$\begingroup\$ @sanyash What do you mean either 0.09 or 0.07, the code clearly outputs 0.16. \$\endgroup\$
    – Peilonrayz
    Mar 11 '20 at 12:28
  • \$\begingroup\$ @Peilonrayz ahh okay I misread the code somehow. My bad. \$\endgroup\$
    – pepoluan
    Mar 24 '20 at 11:34
18
\$\begingroup\$

It's standard to indent Python with 4 spaces. Not following this standard only makes your life and the life of people that have to interact with you harder.

You can just use the optional default argument to dict.get to remove the need for the if.

for k1, v1 in dict1.items():
    for k2, v2 in dict2.items():
        key = k1 + k2
        dict_merged[key] = v1 * v2 + dict_merged.get(key, 0)

Alternately you can change dict_merged to a collections.defaultdict, rather than a dict. This removes the need to use dict.get, and allows you to just us +=. defaultdict takes a function that provides the default value to use. Since int() returns 0, we can just pass int as the function. As noted by Ilmari Karonen you can also use float as that returns 0.0 without any arguments.

import collections

dict_merged = collections.defaultdict(int)
for k1, v1 in dict1.items():
    for k2, v2 in dict2.items():
        dict_merged[k1 + k2] += v1 * v2
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Thank you very much! I didn't know you could default a get value. \$\endgroup\$
    – gjdpm1
    Mar 10 '20 at 16:58
  • \$\begingroup\$ float with no arguments also returns 0.0 and would probably be a more appropriate default factory for the OP, since their actual values all seem to be floats. \$\endgroup\$ Mar 11 '20 at 15:35
  • 2
    \$\begingroup\$ I really wouldn't recommend defaultdict (at least without changing it back into a normal dict), since later on when you actually use it, you'll get 0 instead of a key error when you try to get something that's not there. \$\endgroup\$ Mar 11 '20 at 15:57
  • \$\begingroup\$ @Noctiphobia I've used defaultdict plenty of times, and haven't experienced that issue. \$\endgroup\$
    – Peilonrayz
    Mar 11 '20 at 16:07
  • 1
    \$\begingroup\$ @Cal And that's why I provided two alternates... \$\endgroup\$
    – Peilonrayz
    Mar 11 '20 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.