Как объединить два словаря в одном выражении? - PullRequest
3974 голосов
/ 02 сентября 2008

У меня есть два словаря Python, и я хочу написать одно выражение, которое возвращает эти два словаря, объединенные. Метод update() был бы тем, что мне нужно, если бы он возвратил свой результат вместо того, чтобы изменять диктат на месте.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

Как я могу получить этот последний объединенный диктат в z, а не x?

(Для большей ясности, обработка конфликта «последние один выиграл» dict.update() - это то, что я тоже ищу.)

Ответы [ 40 ]

50 голосов
/ 27 февраля 2015

Python 3.5 (PEP 448) допускает более приятную синтаксическую опцию:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Или даже

final = {'a': 1, 'b': 1, **x, **y}
50 голосов
/ 02 сентября 2008
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

Для элементов с ключами в обоих словарях ('b') вы можете контролировать, какой из них окажется в выводе, поместив этот последний.

40 голосов
/ 14 октября 2011

Хотя на вопрос уже отвечали несколько раз, это простое решение проблемы еще не было перечислено.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

Это так же быстро, как z0 и злой z2, упомянутые выше, но легко понять и изменить.

38 голосов
/ 06 августа 2012
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Среди таких сомнительных и сомнительных ответов этот яркий пример - единственный и единственный хороший способ объединения диктов в Python, одобренный диктатором на всю жизнь Гвидо ван Россум сам! Кто-то предложил половину этого, но не включил его в функцию.

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

дает:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
32 голосов
/ 23 ноября 2011

Если вы думаете, что лямбды - это зло, не читайте дальше. По запросу вы можете написать быстрое и эффективное для памяти решение с одним выражением:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

Как предложено выше, лучше всего использовать две строки или написать функцию.

26 голосов
/ 20 января 2016

Будьте питонами. Используйте понимание :

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}
24 голосов
/ 09 октября 2013

В python3 метод items больше не возвращает список , а скорее представление , которое действует как набор. В этом случае вам нужно взять объединение множеств, так как объединение с + не будет работать:

dict(x.items() | y.items())

Для Python3-подобного поведения в версии 2.7 метод viewitems должен работать вместо items:

dict(x.viewitems() | y.viewitems())

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

Edit:

Еще пара моментов для Python 3. Во-первых, обратите внимание, что трюк dict(x, **y) не будет работать в Python 3, если ключи в y не являются строками.

Кроме того, Chainmap Раймонда Хеттингера answer довольно элегантно, поскольку может принимать в качестве аргументов произвольное количество диктов, но из документов похоже, что последовательно просматривает список из всех диктов для каждого поиска:

Поиск выполняет последовательный поиск соответствующих отображений, пока не будет найден ключ.

Это может замедлить вас, если в вашем приложении много поисков:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Так что примерно на порядок медленнее для поисков. Я фанат Chainmap, но выглядит менее практичным там, где может быть много поисков.

18 голосов
/ 04 августа 2015

Простое решение с использованием itertools, которое сохраняет порядок (последние имеют приоритет)

import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))

И это использование:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}
18 голосов
/ 08 августа 2013

Злоупотребление, приводящее к решению с одним выражением для Ответ Мэтью :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

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

Вы также можете сделать это, если не хотите копировать:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
18 голосов
/ 17 октября 2012

Два словаря

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n словари

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

sum имеет плохую производительность. Смотри https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...