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\$
  • 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 at 1:59
  • 2
    \$\begingroup\$ @pepoluan strange advice, since the code here doesn't require the dictionaries to be sorted. \$\endgroup\$ – Peilonrayz Mar 11 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 at 12:28
  • \$\begingroup\$ @Peilonrayz ahh okay I misread the code somehow. My bad. \$\endgroup\$ – pepoluan Mar 24 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
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thank you very much! I didn't know you could default a get value. \$\endgroup\$ – gjdpm1 Mar 10 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\$ – Ilmari Karonen Mar 11 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\$ – Noctiphobia Mar 11 at 15:57
  • \$\begingroup\$ @Noctiphobia I've used defaultdict plenty of times, and haven't experienced that issue. \$\endgroup\$ – Peilonrayz Mar 11 at 16:07
  • 1
    \$\begingroup\$ @Cal And that's why I provided two alternates... \$\endgroup\$ – Peilonrayz Mar 11 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.