How best to merge the values from multiple dictionaries?

有些话、适合烂在心里 提交于 2020-06-16 04:08:19

问题


I created a function that accepts multiple arguments of dictionaries, and returns a concatenated dictionary. I researched online for a while about concatenating a merging dictionaries and tested the interesting ones. They all resulted in updating the values (or overwriting them).

My use case is passing in dictionaries where each key has a single value, and want a dictionary with the same or different keys, with a list of values for each key. That is my definition of what a so-called "concatenation" of dictionaries would look like.

Here are two very basic dictionaries:

a = {1: 'a', 2: 'b', 3: 'c'}
b = {1: 'd', 2: 'e', 3: 'f'}

Here is the function:

def merge_dict(*args:dict):

    result = {}

    for arg in args:

        if not isinstance(arg, dict):
            return {}

        result_keys = result.keys()
        for key, value in arg.items():
            if key not in result_keys:
                result[key] = [value]
            else:
                result[key].append(value)

    return result

The output is:

print(merge_dict(a, b))
{1: ['a', 'd'], 2: ['b', 'e'], 3: ['c', 'f']}

I could do the same for tuples, or arrays, Numpy arrays, etc. Note this function is very simple and doesn't sanitize input or validate the data structure further than it being a dict instance.

But, I would like to know if there is a more efficient or "pythonic" way of doing this. Please feel free to add your input.

Consider adding these dictionaries with different keys:

c = {4: 'g', 5: 'h', 6: 'i'}
d = {4: 'j', 5: 'k', 6: 'l'}

The output is:

print(merge_dict(a, b, c, d))
{1: ['a', 'd'], 2: ['b', 'e'], 3: ['c', 'f'], 4: ['g', 'j'], 5: ['h', 'k'], 6: ['i', 'l']}

I will work on nested data structures soon.

Because of your answers, here is what I did:

import collections

def merge_dicts_1(*args):
    rtn = collections.defaultdict(list)
    for input_dict in args:
        for key, value in input_dict.items():
            rtn[key].append(value)
    return rtn

def merge_dicts_2(*args):
    rtn = {}
    for input_dict in args:
        for key, value in input_dict.items():
            rtn.setdefault(key, []).append(value)
    return rtn

if __name__ == "__main__":
    a = {1: 'a', 2: 'b', 3: 'c'}
    b = {1: 'd', 2: 'e', 3: 'f'}
    c = {4: 'g', 5: 'h', 6: 'i'}
    d = {4: 'j', 5: 'k', 6: 'l'}
    e = merge_dicts_1(a, b, c, d)
    f = merge_dicts_2(a, b, c, d)
    print(e)
    print(f)
    print(e == f)

This prints the following:

defaultdict(<class 'list'>, {1: ['a', 'd'], 2: ['b', 'e'], 3: ['c', 'f'], 4: ['g', 'j'], 5: ['h', 'k'], 6: ['i', 'l']})
{1: ['a', 'd'], 2: ['b', 'e'], 3: ['c', 'f'], 4: ['g', 'j'], 5: ['h', 'k'], 6: ['i', 'l']}
True

Thank you!


回答1:


Something like this would work for any number of input dictionaries:

import collections

def merge_dicts(*args):
    rtn = collections.defaultdict(list)
    for input_dict in args:
        for key, value in input_dict.items():
            rtn[key].append(value)
    return rtn

The trick is using the defaultdict structure to automatically make new entries when they don't exist. In this case, accessing a key that doesn't yet exist creates it as an empty list.

Note that the above returns a defaultdict object. If this isn't desirable, you can cast it back to dict or use this function instead:

def merge_dicts(*args):
    rtn = {}
    for input_dict in args:
        for key, value in input_dict.items():
            rtn.setdefault(key, []).append(value)
    return rtn



回答2:


How about something like this?

from functools import reduce

def _merge_two_dicts(combined, dictionary):
    for key, value in dictionary.items():
        combined.setdefault(key, []).append(value)
    return combined

def merge_dicts(*dicts):
    return reduce(_merge_two_dicts, dicts, {})


if __name__ == '__main__':
    a = {1: 'a', 2: 'b', 3: 'c'}
    b = {1: 'd', 2: 'e', 3: 'f', 4: 'g'}
    c = {1: 'h', 3: 'i', 5: 'j'}

    combined = merge_dicts(a, b, c)
    print(combined)    

Output:

{1: ['a', 'd', 'h'], 2: ['b', 'e'], 3: ['c', 'f', 'i'], 4: ['g'], 5: ['j']}


来源:https://stackoverflow.com/questions/53109960/how-best-to-merge-the-values-from-multiple-dictionaries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!