Как лучше всего объединить значения из нескольких словарей? - PullRequest
0 голосов
/ 02 ноября 2018

Я создал функцию, которая принимает несколько аргументов словарей и возвращает объединенный словарь. Некоторое время я проводил онлайн-исследования по объединению словарей слияния и проверял интересные. Все они привели к обновлению значений (или их перезаписи).

Мой вариант использования заключается в передаче словарей, в которых каждый ключ имеет одно значение, и требуется словарь с одинаковыми или разными ключами со списком значений для каждого ключа. Это мое определение того, как должна выглядеть так называемая «конкатенация» словарей.

Вот два очень простых словаря:

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

Вот функция:

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

Вывод:

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

Я мог бы сделать то же самое для кортежей или массивов, массивов Numpy и т. Д. Обратите внимание, что эта функция очень проста и не дезинфицирует ввод и не проверяет структуру данных дальше, чем dict экземпляр.

Но я хотел бы знать, есть ли более эффективный или "питонический" способ сделать это. Пожалуйста, не стесняйтесь добавлять свой вклад.

Рассмотрите возможность добавления этих словарей с разными ключами:

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

Вывод:

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']}

Я скоро поработаю над вложенными структурами данных.

Из-за ваших ответов вот что я сделал:

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)

Это печатает следующее:

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

Спасибо!

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Примерно так будет работать для любого количества входных словарей:

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

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

Обратите внимание, что приведенное выше возвращает объект defaultdict. Если это нежелательно, вы можете привести его обратно к dict или использовать эту функцию:

def merge_dicts(*args):
    rtn = {}
    for input_dict in args:
        for key, value in input_dict.items():
            rtn.setdefault(key, []).append(value)
    return rtn
0 голосов
/ 02 ноября 2018

Как насчет этого?

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)    

Выход:

{1: ['a', 'd', 'h'], 2: ['b', 'e'], 3: ['c', 'f', 'i'], 4: ['g'], 5: ['j']}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...