2

Thanks to @naivepredictor's comment, I find that my question is ambiguous and equivocal.

I want to merge two nested and deep dictories.It is similar to How to merge two dictionaries in a single expression?, but different to it, I want to merge two values to one list when merging. It is similar to Merge two dictionaries and keep the values for duplicate keys in Python, but dict in here is nested and deep. as follows: For example:

dic_a = {
    'a1': {'a2': {'a3': 4}},
    'a11': {'a2': {'a3': 4}},
    'a111': {'a2': {'a3': 4}},
    'a1111': {'a2': {'a3': 4}}
}
dic_b = {
    'a1': {'a2': {'a3': [4, 9]}},
    'b1': {'b2': {'b3': 99}},
    'b11': {'b2': {'b3': 99}},
    'b111': {'b2': {'b3': 99}},
    'b1111': {'b2': {'b3': 99}}
}

print(merged_dict)
"""
{'a1': {'a2': {'a3': [4, 4, 9]}},
 'a11': {'a2': {'a3': 4}},
 'a111': {'a2': {'a3': 4}},
 'a1111': {'a2': {'a3': 4}},
 'b1': {'b2': {'b3': 99}},
 'b11': {'b2': {'b3': 99}},
 'b111': {'b2': {'b3': 99}},
 'b1111': {'b2': {'b3': 99}}}
"""

I have implemented an merge_dicts with recursion. as follows.

from copy import deepcopy


def _add_value_to_list(value, lis):
    if value:
        if isinstance(value, list):
            lis.extend(value)
        else:
            lis.append(value)
    else:
        pass


def _merge_value(value_a, value_b):
    merged_value = []
    _add_value_to_list(value_a, merged_value)
    _add_value_to_list(value_b, merged_value)
    return merged_value


def _recursion_merge_dict(new_dic, dic_a, dic_b):
    if not dic_a or not dic_b:
        return new_dic
    else:
        if isinstance(new_dic, dict):
            for k, v in new_dic.items():
                new_dic[k] = _recursion_merge_dict(v, dic_a.get(k, {}), dic_b.get(k, {}))
            return new_dic
        else:
            return _merge_value(dic_a, dic_b)


def merge_dicts(dic_a, dic_b):
    new_dic = deepcopy(dic_a)
    new_dic.update(dic_b)

    return _recursion_merge_dict(new_dic, dic_a, dic_b)

But it run slowly, I need a more quick one. Thank you.

The leaf values of dictionaries needed to be merged just belong to list or unicode.

Happy Boy
  • 526
  • 2
  • 9
  • This question is different to [How to merge two dictionaries in a single expression?](https://stackoverflow.com/questions/38987/how-to-merge-two-dictionaries-in-a-single-expression). – Happy Boy Mar 01 '19 at 07:53
  • Possible duplicate of [Merge two dictionaries and keep the values for duplicate keys in Python](https://stackoverflow.com/questions/52562882/merge-two-dictionaries-and-keep-the-values-for-duplicate-keys-in-python) – naivepredictor Mar 01 '19 at 08:06
  • They are so similar. But there are still a little difference: the dict in my question is nested, and deep. – Happy Boy Mar 01 '19 at 08:16
  • 2
    Dictionaries in your question are not nested and are not deep.Each of the dictionaries in the question have one key and one value. – naivepredictor Mar 01 '19 at 08:22
  • So sorry. This is second time to ask the same question. First time, I use nested dictionaries, but many reviewer think it is duplicate to another question. So this time i give a simple example. But you can see that: My code is recursion, so the dictionary must be nested and deep. – Happy Boy Mar 01 '19 at 08:29
  • Ask question in a simple way if you want to get clear answer. You are moving goal post after you asked the question. Don't overcomplicate things. If people think your question is duplicate then there is high probability your question is duplicate. – naivepredictor Mar 01 '19 at 08:32
  • Provide the link to your previous question in which you asked about nested dictionaries to shed some more light on your problem. – naivepredictor Mar 01 '19 at 08:33
  • Ok, i will reedit my question to clear my question, thank you. My previous question had deleted by me after posting this question. – Happy Boy Mar 01 '19 at 08:37

2 Answers2

0

Try this :

dic_a = { 'a1': '4'}
dic_b = { 'a1': '9'}
def merge_dicts(dict_a, dict_b):
    return { k : list(filter(lambda x: x is not None, [dic_a[k] if (k in dic_a) else None]+[dic_b[k] if (k in dic_b) else None])) for k in set(list(dic_a.keys()) + list(dic_b.keys()))}
merge_dicts(dic_a, dic_b)    # {'a1': ['4', '9']}

Works for dictionaries with multiple keys also :

dic_a = {'a1': '19', 'b1': 564, 'c1': 5641}
dic_b = {'a1': '9', 'b1': 4, 'c1': 5, 'd1' : 0}
merge_dicts(dic_a, dic_b)    # {'b1': [564, 4], 'c1': [5641, 5], 'a1': ['19', '9'], 'd1': [0]}
Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
0
def merger(dic_a, dic_b):
    dic_merged = {}
    for i in dic_a:
        if i in dic_b:
            dic_merged[i] = [dic_a[i]] + [dic_b[i]]
        else:
            dic_merged[i] = dic_a[i]
    for i in dic_b:
        if i not in dic_a:
            dic_merged[i] = dic_b[i]
    return (dic_merged)
merger(dic_a, dic_b)
Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
Lukas Kaspras
  • 409
  • 1
  • 5
  • 15