5

Есть ли питоний способ объединить два словаря (сложив значения для ключей, которые присутствуют в обоих)?

16

Задача заключается в следующем: у меня есть два словаря:

Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}

Мне нужно "объединить" эти два словаря таким образом, чтобы результатом был следующий словарь:

{'a': 1, 'b': 5, 'c': 7, 'd': 5}

То есть, если ключ присутствует в обоих словарях, необходимо сложить их значения. Если же ключ есть только в одном из словарей, нужно сохранить его значение.

Как я могу реализовать это на Python, используя при этом "питонистичный" подход?

5 ответ(ов)

1

Для более общего решения, которое работает с нечисловыми значениями, вы можете использовать следующий код:

a = {'a': 'foo', 'b': 'bar', 'c': 'baz'}
b = {'a': 'spam', 'c': 'ham', 'x': 'blah'}

r = dict(list(a.items()) + list(b.items()) +
    [(k, a[k] + b[k]) for k in set(b) & set(a)])

Либо еще более универсальное решение:

import operator

def combine_dicts(a, b, op=operator.add):
    return dict(list(a.items()) + list(b.items()) +
        [(k, op(a[k], b[k])) for k in set(b) & set(a)])

Например, если вы выполните следующий код:

>>> a = {'a': 2, 'b': 3, 'c': 4}
>>> b = {'a': 5, 'c': 6, 'x': 7}

>>> print(combine_dicts(a, b, operator.mul))
{'a': 10, 'x': 7, 'c': 24, 'b': 3}

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

0

Вы можете объединить два словаря A и B и суммировать значения по общим ключам следующим образом:

A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}
c = {x: A.get(x, 0) + B.get(x, 0) for x in set(A).union(B)}
print(c)

На выходе вы получите следующее:

{'a': 1, 'c': 7, 'b': 5, 'd': 5}

В этом коде мы создаем новый словарь c, где для каждого ключа x, который находится в объединении ключей из обоих словарей, мы используем метод get() для получения значений. Если ключа нет в одном из словарей, будет возвращено значение по умолчанию, равное 0. Таким образом, мы суммируем значения по общим ключам и добавляем ключи, которые есть только в одном из словарей.

0

Введение: Существует множество (возможно, лучших) решений различных задач. Но нужно знать их и помнить, и иногда надеяться, что ваша версия Python не слишком старая или что-то в этом роде.

Затем есть более "хакерские" решения. Они отличные и короткие, но иногда трудны для понимания, чтения и запоминания.

Тем не менее, есть альтернатива: попробовать reinvent the wheel (изобрести колесо заново).

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

Итак, я предлагаю reinvent the wheel для класса Counter из модуля collections (по крайней мере, частично):

class MyDict(dict):
    def __add__(self, oth):
        r = self.copy()

        try:
            for key, val in oth.items():
                if key in r:
                    r[key] += val  # Здесь можно изменить логику
                else:
                    r[key] = val
        except AttributeError:  # На случай, если oth не является словарем
            return NotImplemented  # Конвенция для необработанных случаев

        return r

a = MyDict({'a': 1, 'b': 2, 'c': 3})
b = MyDict({'b': 3, 'c': 4, 'd': 5})

print(a + b)  # Вывод: {'a': 1, 'b': 5, 'c': 7, 'd': 5}

Существуют, вероятно, и другие способы реализации этого, уже есть инструменты, которые это делают, но всегда приятно визуализировать, как все это будет работать в своем базовом виде.

0

Определенно, складывать объекты Counter() — это самый "питоничный" способ в подобных случаях, но только если это приводит к положительному значению. Вот пример: как вы можете видеть, после отрицания значения c в словаре B в результате отсутствует c.

In [1]: from collections import Counter

In [2]: A = Counter({'a':1, 'b':2, 'c':3})

In [3]: B = Counter({'b':3, 'c':-4, 'd':5})

In [4]: A + B
Out[4]: Counter({'d': 5, 'b': 5, 'a': 1})

Это происходит потому, что Counter изначально был разработан для работы с положительными целыми числами, представляющими количество (отрицательное количество не имеет смысла). Чтобы помочь с такими случаями, в Python описаны минимальные ограничения диапазона и типа следующим образом:

  • Класс Counter сам по себе является подклассом словаря, и для его ключей и значений нет ограничений. Значения предназначены для представления количеств, но вы можете сохранять в них что угодно.
  • Метод most_common() требует только, чтобы значения были упорядочиваемыми.
  • Для операций на месте, таких как c[key] += 1, тип значения должен поддерживать только операции сложения и вычитания. Таким образом, дроби, числа с плавающей запятой и десятичные числа подойдут, и отрицательные значения поддерживаются. То же самое касается методов update() и subtract(), которые допускают отрицательные и нулевые значения для входных и выходных данных.
  • Методы мультисетов предназначены только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но создаются только выходные данные с положительными значениями. Ограничений по типам нет, но тип значения должен поддерживать сложение, вычитание и сравнение.
  • Метод elements() требует целых количеств. Он игнорирует нулевые и отрицательные количества.

Таким образом, чтобы обойти эту проблему после сложения ваших Counter, вы можете использовать Counter.update, чтобы получить желаемый результат. Это работает как dict.update(), но добавляет количества, а не заменяет их.

In [24]: A.update(B)

In [25]: A
Out[25]: Counter({'d': 5, 'b': 5, 'a': 1, 'c': -1})
0

Ваш код создает новый словарь myDict, который суммирует значения из двух других словарей A и B по ключам.

Вот краткое объяснение вашего кода:

  1. Вы создаете пустой словарь myDict.
  2. Используя itertools.chain, вы объединяете ключи из обоих словарей A и B.
  3. В цикле вы проходите по всем ключам и добавляете их в myDict. Для каждого ключа k вы используете метод get, чтобы получить значения из A и B. Если ключа нет в каком-либо из словарей, будет возвращено значение 0 (это позволяет избежать ошибок при обращении к несуществующим ключам).
  4. Таким образом, итоговое значение для ключа k в myDict будет равно сумме значений из словарей A и B.

Если вам требуется другое объяснение или уточнение, пожалуйста, дайте знать!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь