Объедините два словаря и сохраните значения для дубликатов ключей в Python - PullRequest
0 голосов
/ 29 сентября 2018

Давайте предположим, что у меня есть два словаря:

dic1 =  { "first":1, "second":4, "third":8} 
dic2 =  { "first":9, "second":5, "fourth":3}

Есть ли простой способ получить что-то похожее на приведенное ниже?

dic3 =  { "first":[1,9], "second":[4,5], "third":[8], "fourth":[3]}

Я использовал списки для хранения значений, но кортежи тоже подойдут.

Ответы [ 7 ]

0 голосов
/ 29 сентября 2018

Использование набора и словарного понимания

L = [d1, d2]
dups = set(d1.keys() & d2.keys())
d = {k: [L[0][k], L[1][k]] if k in dups else i[k] for i in L for k in i}
{'first': [1, 9], 'second': [4, 5], 'third': 8, 'fourth': 3}
0 голосов
/ 01 марта 2019
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)
0 голосов
/ 29 сентября 2018

Создайте новый словарь dic, имеющий для ключей ключи dic1 и dic2 и значение пустого списка, затем итерируйте по dic1 и dic2, добавляя значения к dic:

dic1 =  { "first":1, "second":4, "third":8} 
dic2 =  { "first":9, "second":5, "fourth":3}

dic = {key:[] for key in list(dic1.keys()) + list(dic2.keys())}

for key in dic1.keys():
    dic[key].append(dic1[key])

for key in dic2.keys():
    dic[key].append(dic2[key])
0 голосов
/ 29 сентября 2018

Дано:

dic1 =  { "first":1, "second":4, "third":8} 
dic2 =  { "first":9, "second":5, "fourth":3}

Вы можете использовать .setdefault:

dic_new={}
for k,v in list(dic1.items())+list(dic2.items()):
    dic_new.setdefault(k, []).append(v)
else:
    dic_new={k:v if len(v)>1 else v[0] for k,v in dic_new.items()}  

>>> dic_new
{'first': [1, 9], 'second': [4, 5], 'third': 8, 'fourth': 3}

.Я думаю, что сведение списков отдельных элементов к другому типу объекта является ненужной сложностью.


При редактировании это дает желаемый результат:

dic_new={}
for k,v in list(dic1.items())+list(dic2.items()):
    dic_new.setdefault(k, []).append(v)

>>> dic_new
{'first': [1, 9], 'second': [4, 5], 'third': [8], 'fourth': [3]}
0 голосов
/ 29 сентября 2018

В целом, я бы сказал, что это плохая практика - приводить значения разных ключей как разные типы объектов.Я бы просто сделал что-то вроде:

def merge_values(val1, val2):
    if val1 is None:
        return [val2]
    elif val2 is None:
        return [val1]
    else:
        return [val1, val2]
dict3 = {
    key: merge_values(dic1.get(key), dic2.get(key))
    for key in set(dic1).union(dic2)
}
0 голосов
/ 29 сентября 2018

Вот наивное решение;скопируйте один из словарей в результат и переберите ключи и значения другого словаря, добавляя массивы к результату по мере необходимости.Поскольку существует только два словаря, ни один массив слияний не будет иметь более 2 элементов;нет необходимости проверять тип.

dic1 = {"first": 1, "second": 4, "third": 8} 
dic2 = {"first": 9, "second": 5, "fourth": 3}
dic3 = dict(dic2)

for k, v in dic1.items():
    dic3[k] = [dic3[k], v] if k in dic3 else v

print(dic3)

Вывод:

{'first': [9, 1], 'second': [5, 4], 'fourth': 3, 'third': 8}

Попробуйте .

Если вы хотите, чтобы отдельные значениябыть списки, которые вы можете использовать:

dic3 = {k: [v] for k, v in dic2.items()}

for k, v in dic1.items():
    dic3[k] = dic3[k] + [v] if k in dic3 else [v]
0 голосов
/ 29 сентября 2018

Вы можете использовать defaultdict для хранения списков, а затем просто добавлять значения к ним.Этот подход легко распространяется на произвольное количество словарей.

from collections import defaultdict

dd = defaultdict(list)

dics = [dic1, dic2]
for dic in dics:
    for key, val in dic.iteritems():  # .items() in Python 3.
        dd[key].append(val)

>>> dict(dd)
{'first': [1, 9], 'fourth': [3], 'second': [4, 5], 'third': [8]}

Все ключи с одним значением по-прежнему хранятся в списке, что, вероятно, является наилучшим способом.Вы можете, однако, изменить что-либо длины один на фактическое значение, например

for key, val in dd.iteritems():  # .items() in Python 3.
    if len(val) == 1
        dd[key] = val[0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...