2

I need to append the values from one dictionary (N) to another (M) - pseudocode below

if[x] in M:
  M[x]=M[x]+N[x]
else:
  M[x]=N[x] 

Doing this for every key in N seems quite untidy coding.
What would be the most efficient way to achieve this?

erip
  • 16,374
  • 11
  • 66
  • 121
IUnknown
  • 9,301
  • 15
  • 50
  • 76
  • @hiroprotagonist update will overwrite, i don't think Op want to overwrite. – Hackaholic May 02 '17 at 12:13
  • @Hackaholic oops you are right... i should read more than the title... will delete. – hiro protagonist May 02 '17 at 12:15
  • Checkout `defaultdict` https://docs.python.org/3/library/collections.html#collections.defaultdict – Chris_Rands May 02 '17 at 12:24
  • I fail to see how "defaultdict" could simplify anything here. Can you be more explicit? That is because defaultdict won't allow you to provide a custom expression for value if the key already exists in the dictionary. – jsbueno May 02 '17 at 12:31

3 Answers3

3

Of course you should be iterating your keys in "x" already - but a single line solution is:

M.update({key:((M[key] + value) if key in M else value) for key, value in N.items()})
jsbueno
  • 99,910
  • 10
  • 151
  • 209
1

not entirely sure what your x is (guessing the keys of both M and N), then this might work:

M = {key: M.get(key, 0) + N.get(key, 0) for key in set((*M, *N))}

for the example:

M = {'a': 1, 'c': 3, 'e': 5}
N = {'a': 2, 'b': 4, 'c': 6, 'd': 8}

you get:

print(M)  # {'a': 3, 'e': 5, 'd': 8, 'c': 9, 'b': 4}

or please clarify what the desired output for the given example would be.

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
  • FWIW, this is similar to [Alex's solution](http://stackoverflow.com/a/1495821/4014959), which is a bit outdated (so no longer a good dupe target). – PM 2Ring May 02 '17 at 13:00
  • 1
    @PM2Ring: thanks, did not know that post. yes, my solution works with `int` only; @jsbueno 's works with anything that has an `__add__` method; the dict could even have mixed values. – hiro protagonist May 02 '17 at 13:56
1

When you say "append", I assume that means that the values in your dicts are lists. However the techniques below can easily be adapted if they're simple objects like integers or strings.

Python doesn't provide any built-in methods for handling dicts of lists, and the most efficient way to do this depends on the data, because some ways work best when there are a high proportion of shared keys, other ways are better when there aren't many shared keys.

If the proportion of shared keys isn't too high, this code is reasonably efficient:

m = {1:[1, 2], 2:[3]}
n = {1:[4], 3:[5]}

for k, v in n.items():
    m.setdefault(k, []).extend(v)

print(m)

output

{1: [1, 2, 4], 2: [3], 3: [5]}

You can make this slightly faster by caching the .setdefault method and the empty list:

def merge(m, n):
    setdef = m.setdefault
    empty = []
    for k, v in n.items():
        setdef(k, empty).extend(v)

If you expect a high proportion of shared keys, then it's better to perform set operations on the keys (in Python 3, dict.keys() return a set-like View object, which is extremely efficient to construct), and handle the shared keys separately from the unique keys of N.

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • ha! i was trying to use `setdefault` and failed. came up with a solution using `get`. but this is nice! +1 – hiro protagonist May 02 '17 at 12:54
  • @hiroprotagonist Thanks! I've recently fallen in love with `setdefault`. :) Why `defaultdict` when you can `setdefault`? – PM 2Ring May 02 '17 at 12:57
  • @hiroprotagonist I just realised that the OP didn't actually say their dict values are lists. Oops! :) I guess I can add to my answer if it turns out that I guessed incorrectly... – PM 2Ring May 02 '17 at 13:03