Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?

前端 未结 17 2348
梦毁少年i
梦毁少年i 2020-11-22 01:50

For example I have two dicts:

Dict A: {\'a\': 1, \'b\': 2, \'c\': 3}
Dict B: {\'b\': 3, \'c\': 4, \'d\': 5}

I need a pythonic way of \'comb

相关标签:
17条回答
  • 2020-11-22 02:42

    This solution is easy to use, it is used as a normal dictionary, but you can use the sum function.

    class SumDict(dict):
        def __add__(self, y):
            return {x: self.get(x, 0) + y.get(x, 0) for x in set(self).union(y)}
    
    A = SumDict({'a': 1, 'c': 2})
    B = SumDict({'b': 3, 'c': 4})  # Also works: B = {'b': 3, 'c': 4}
    print(A + B)  # OUTPUT {'a': 1, 'b': 3, 'c': 6}
    
    0 讨论(0)
  • 2020-11-22 02:45

    Use collections.Counter:

    >>> from collections import Counter
    >>> A = Counter({'a':1, 'b':2, 'c':3})
    >>> B = Counter({'b':3, 'c':4, 'd':5})
    >>> A + B
    Counter({'c': 7, 'b': 5, 'd': 5, 'a': 1})
    

    Counters are basically a subclass of dict, so you can still do everything else with them you'd normally do with that type, such as iterate over their keys and values.

    0 讨论(0)
  • 2020-11-22 02:47

    A more generic solution, which works for non-numeric values as well:

    a = {'a': 'foo', 'b':'bar', 'c': 'baz'}
    b = {'a': 'spam', 'c':'ham', 'x': 'blah'}
    
    r = dict(a.items() + b.items() +
        [(k, a[k] + b[k]) for k in set(b) & set(a)])
    

    or even more generic:

    def combine_dicts(a, b, op=operator.add):
        return dict(a.items() + b.items() +
            [(k, op(a[k], b[k])) for k in set(b) & set(a)])
    

    For example:

    >>> a = {'a': 2, 'b':3, 'c':4}
    >>> b = {'a': 5, 'c':6, 'x':7}
    
    >>> import operator
    >>> print combine_dicts(a, b, operator.mul)
    {'a': 10, 'x': 7, 'c': 24, 'b': 3}
    
    0 讨论(0)
  • 2020-11-22 02:49

    Intro: There are the (probably) best solutions. But you have to know it and remember it and sometimes you have to hope that your Python version isn't too old or whatever the issue could be.

    Then there are the most 'hacky' solutions. They are great and short but sometimes are hard to understand, to read and to remember.

    There is, though, an alternative which is to to try to reinvent the wheel. - Why reinventing the wheel? - Generally because it's a really good way to learn (and sometimes just because the already-existing tool doesn't do exactly what you would like and/or the way you would like it) and the easiest way if you don't know or don't remember the perfect tool for your problem.

    So, I propose to reinvent the wheel of the Counter class from the collections module (partially at least):

    class MyDict(dict):
        def __add__(self, oth):
            r = self.copy()
    
            try:
                for key, val in oth.items():
                    if key in r:
                        r[key] += val  # You can custom it here
                    else:
                        r[key] = val
            except AttributeError:  # In case oth isn't a dict
                return NotImplemented  # The convention when a case isn't handled
    
            return r
    
    a = MyDict({'a':1, 'b':2, 'c':3})
    b = MyDict({'b':3, 'c':4, 'd':5})
    
    print(a+b)  # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}
    

    There would probably others way to implement that and there are already tools to do that but it's always nice to visualize how things would basically works.

    0 讨论(0)
  • 2020-11-22 02:50

    From python 3.5: merging and summing

    Thanks to @tokeinizer_fsj that told me in a comment that I didn't get completely the meaning of the question (I thought that add meant just adding keys that eventually where different in the two dictinaries and, instead, i meant that the common key values should be summed). So I added that loop before the merging, so that the second dictionary contains the sum of the common keys. The last dictionary will be the one whose values will last in the new dictionary that is the result of the merging of the two, so I thing the problem is solved. The solution is valid from python 3.5 and following versions.

    a = {
        "a": 1,
        "b": 2,
        "c": 3
    }
    
    b = {
        "a": 2,
        "b": 3,
        "d": 5
    }
    
    # Python 3.5
    
    for key in b:
        if key in a:
            b[key] = b[key] + a[key]
    
    c = {**a, **b}
    print(c)
    
    >>> c
    {'a': 3, 'b': 5, 'c': 3, 'd': 5}
    

    Reusable code

    a = {'a': 1, 'b': 2, 'c': 3}
    b = {'b': 3, 'c': 4, 'd': 5}
    
    
    def mergsum(a, b):
        for k in b:
            if k in a:
                b[k] = b[k] + a[k]
        c = {**a, **b}
        return c
    
    
    print(mergsum(a, b))
    
    0 讨论(0)
  • 2020-11-22 02:51
    >>> A = {'a':1, 'b':2, 'c':3}
    >>> B = {'b':3, 'c':4, 'd':5}
    >>> c = {x: A.get(x, 0) + B.get(x, 0) for x in set(A).union(B)}
    >>> print(c)
    
    {'a': 1, 'c': 7, 'b': 5, 'd': 5}
    
    0 讨论(0)
提交回复
热议问题