← Назад к вопросам
Объединение словарей с суммированием
1.6 Junior🔥 171 комментариев
#Python Core
Условие
Напишите функцию, которая объединяет два словаря. Если ключ есть в обоих словарях, значения суммируются.
Пример
merge_dicts({"a": 1, "b": 2}, {"b": 3, "c": 4}) → {"a": 1, "b": 5, "c": 4}
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Объединение словарей с суммированием
Эта классическая задача требует объединения двух словарей с агрегацией значений по ключам. Это полезный паттерн при работе с числовыми данными, счётчиками, статистикой и многим другим.
Простое решение
def merge_dicts(dict1: dict, dict2: dict) -> dict:
"""
Объединяет два словаря, суммируя значения по совпадающим ключам.
Args:
dict1: Первый словарь
dict2: Второй словарь
Returns:
Новый словарь с объединёнными данными
Examples:
>>> merge_dicts({"a": 1, "b": 2}, {"b": 3, "c": 4})
{'a': 1, 'b': 5, 'c': 4}
>>> merge_dicts({"x": 10}, {"y": 20})
{'x': 10, 'y': 20}
"""
result = dict1.copy() # Копируем первый словарь
# Проходим по второму словарю и суммируем
for key, value in dict2.items():
if key in result:
result[key] += value
else:
result[key] = value
return result
Решение с использованием get()
def merge_dicts_get(dict1: dict, dict2: dict) -> dict:
"""
Альтернативное решение с использованием метода get().
"""
result = dict1.copy()
for key, value in dict2.items():
# Если ключа нет, get() вернёт 0 (для чисел)
result[key] = result.get(key, 0) + value
return result
Решение с использованием setdefault()
def merge_dicts_setdefault(dict1: dict, dict2: dict) -> dict:
"""
Решение с использованием setdefault().
"""
result = dict1.copy()
for key, value in dict2.items():
# setdefault() возвращает существующее значение или устанавливает новое
result.setdefault(key, 0)
result[key] += value
return result
Решение со слиянием в place (изменение исходного словаря)
def merge_dicts_inplace(dict1: dict, dict2: dict) -> dict:
"""
Объединение со слиянием в исходный словарь.
Примечание: изменяет dict1!
"""
for key, value in dict2.items():
dict1[key] = dict1.get(key, 0) + value
return dict1
Решение с использованием Counter
from collections import Counter
def merge_dicts_counter(dict1: dict, dict2: dict) -> dict:
"""
Решение с использованием Counter из collections.
Очень элегантно и эффективно для целых чисел.
"""
counter1 = Counter(dict1)
counter2 = Counter(dict2)
# Counter поддерживает сложение
result = counter1 + counter2
return dict(result)
Решение с использованием функциональных подходов
from itertools import chain
from functools import reduce
from typing import Dict, Callable
def merge_dicts_reduce(dict1: dict, dict2: dict) -> dict:
"""
Функциональный подход с reduce().
"""
def merge_two(acc, item):
key, value = item
acc[key] = acc.get(key, 0) + value
return acc
# Объединяем все элементы и применяем merge_two
return reduce(merge_two, chain(dict1.items(), dict2.items()), {})
Универсальное решение для любых типов данных
from typing import TypeVar, Callable, Any
K = TypeVar('K') # Тип ключа
V = TypeVar('V') # Тип значения
def merge_dicts_custom(
dict1: dict,
dict2: dict,
merge_func: Callable[[Any, Any], Any] = lambda x, y: x + y
) -> dict:
"""
Универсальное решение с пользовательской функцией слияния.
Args:
dict1: Первый словарь
dict2: Второй словарь
merge_func: Функция для слияния значений (по умолчанию сумма)
Returns:
Объединённый словарь
Examples:
>>> merge_dicts_custom({"a": 1}, {"a": 2}, lambda x, y: x + y)
{'a': 3}
>>> merge_dicts_custom({"a": [1, 2]}, {"a": [3]}, lambda x, y: x + y)
{'a': [1, 2, 3]}
"""
result = dict1.copy()
for key, value in dict2.items():
if key in result:
result[key] = merge_func(result[key], value)
else:
result[key] = value
return result
Примеры использования
# Базовый пример
print(merge_dicts({"a": 1, "b": 2}, {"b": 3, "c": 4}))
# {'a': 1, 'b': 5, 'c': 4}
# Объединение счётчиков
counts1 = {"apple": 5, "banana": 3}
counts2 = {"banana": 2, "orange": 4}
print(merge_dicts(counts1, counts2))
# {'apple': 5, 'banana': 5, 'orange': 4}
# Объединение статистики
stats1 = {"clicks": 100, "impressions": 500}
stats2 = {"clicks": 50, "conversions": 10}
print(merge_dicts(stats1, stats2))
# {'clicks': 150, 'impressions': 500, 'conversions': 10}
# Объединение с пользовательской функцией
data1 = {"x": [1, 2], "y": [3]}
data2 = {"x": [4], "y": [5, 6]}
result = merge_dicts_custom(data1, data2, lambda x, y: x + y)
print(result)
# {'x': [1, 2, 4], 'y': [3, 5, 6]}
# С использованием Counter
freq1 = {"a": 5, "b": 2, "c": 1}
freq2 = {"b": 3, "c": 4, "d": 2}
print(merge_dicts_counter(freq1, freq2))
# {'a': 5, 'b': 5, 'c': 5, 'd': 2}
Тестирование
def test_merge_dicts():
# Базовые случаи
assert merge_dicts({"a": 1, "b": 2}, {"b": 3, "c": 4}) == {"a": 1, "b": 5, "c": 4}
# Без пересечений
assert merge_dicts({"a": 1}, {"b": 2}) == {"a": 1, "b": 2}
# Полное пересечение
assert merge_dicts({"a": 1, "b": 2}, {"a": 3, "b": 4}) == {"a": 4, "b": 6}
# Пустой словарь
assert merge_dicts({}, {"a": 1}) == {"a": 1}
assert merge_dicts({"a": 1}, {}) == {"a": 1}
assert merge_dicts({}, {}) == {}
# Отрицательные числа
assert merge_dicts({"a": 5}, {"a": -3}) == {"a": 2}
# Нулевые значения
assert merge_dicts({"a": 0}, {"a": 5}) == {"a": 5}
print("Все тесты пройдены!")
test_merge_dicts()
Сравнение производительности
import time
from collections import Counter
def benchmark_merge():
dict1 = {f"key_{i}": i for i in range(1000)}
dict2 = {f"key_{i}": i*2 for i in range(500, 1500)}
# Простое решение
start = time.time()
for _ in range(1000):
merge_dicts(dict1, dict2)
simple_time = time.time() - start
# С Counter
start = time.time()
for _ in range(1000):
merge_dicts_counter(dict1, dict2)
counter_time = time.time() - start
print(f"Простое решение: {simple_time:.4f}s")
print(f"Counter: {counter_time:.4f}s")
benchmark_merge()
Анализ сложности
Простое решение:
- Временная сложность: O(n + m), где n и m — размеры словарей
- Пространственная сложность: O(n + m) для нового словаря
Решение с Counter:
- Временная сложность: O(n + m)
- Пространственная сложность: O(n + m)
Оба решения эквивалентны по производительности. Выбирайте в зависимости от читаемости кода и требований к типам данных.
Практическое применение
- Слияние логов: объединение счётчиков событий
- Analytics: агрегация метрик по временным периодам
- Инвентарь: объединение количеств товаров
- Рейтинговые системы: слияние баллов пользователей