Python: Dictionary merge by updating but not overwriting if value exists

前端 未结 7 776
后悔当初
后悔当初 2020-12-15 02:48

If I have 2 dicts as follows:

d1 = {(\'unit1\',\'test1\'):2,(\'unit1\',\'test2\'):4}
d2 = {(\'unit1\',\'test1\'):2,(\'unit1\',\'test2\'):\'\'}
7条回答
  •  伪装坚强ぢ
    2020-12-15 03:16

    Merging Only Non-zero values

    to do this we can just create a dict without the empty values and then merge them together this way:

    d1 = {'a':1, 'b':1, 'c': '', 'd': ''}
    d2 = {'a':2, 'c':2, 'd': ''}
    merged_non_zero = {
        k: (d1.get(k) or d2.get(k))
        for k in set(d1) | set(d2)
    }
    print(merged_non_zero)
    

    outputs:

    {'a': 1, 'b': 1, 'c': 2, 'd': ''}
    
    • a -> prefer first value from d1 as 'a' exists on both d1 and d2
    • b -> only exists on d1
    • c -> non-zero on d2
    • d -> empty string on both

    Explanation

    The above code will create a dictionary using dict comprehension.

    if d1 has the value and its non-zero value (i.e. bool(val) is True), it'll use d1[k] value, otherwise it'll take d2[k].

    notice that we also merge all keys of the two dicts as they may not have the exact same keys using set union - set(d1) | set(d2).

    Python 3.5+ Literal Dict

    unless using obsolete version of python you better off using this.

    Pythonic & faster way for dict unpacking:

    d1 = {'a':1, 'b':1}
    d2 = {'a':2, 'c':2}
    merged = {**d1, **d2}  # priority from right to left
    print(merged)
    
    {'a': 2, 'b': 1, 'c': 2}
    

    its simpler and also faster than the dict(list(d2.items()) + list(d1.items())) alternative:

    d1 = {i: 1 for i in range(1000000)}
    d2 = {i: 2 for i in range(2000000)}
    
    %timeit dict(list(d1.items()) + list(d2.items())) 
    402 ms ± 33.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %timeit {**d1, **d2}
    144 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    more on this from PEP448:

    The keys in a dictionary remain in a right-to-left priority order, so {**{'a': 1}, 'a': 2, **{'a': 3}} evaluates to {'a': 3}. There is no restriction on the number or position of unpackings.

提交回复
热议问题