Как объединить два словаря в одном выражении?

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

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

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

(Чтобы быть экстра-ясным, обработка конфликтов с последними однократными конфликтами dict.update() - это то, что я ищу.)

3407
задан 02 сент. '08 в 10:44
источник поделиться
50 ответов
  • 1
  • 2

Как я могу объединить два словаря Python в одном выражении?

Для словарей x и y z становится объединенным словарем со значениями из y заменяющими те из x.

  • В Python 3.5 или выше:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • В Python 2 (или 3.4 или ниже) напишите функцию:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x keys and values
        z.update(y)    # modifies z with y keys and values & returns None
        return z
    

    а также

    z = merge_two_dicts(x, y)
    

объяснение

Скажем, у вас есть два диктата, и вы хотите объединить их в новый дикт, не изменяя исходные слова:

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

Желательным результатом является получение нового словаря (z) с объединенными значениями, а во втором дикторе значения будут записаны с первого.

>>> z
{'a': 1, 'b': 3, 'c': 4}

Новый синтаксис для этого, предложенный в PEP 448 и доступный с Python 3.5,

z = {**x, **y}

И это действительно одно выражение. В настоящее время он отображается как реализованный в расписании релиза для 3.5, PEP 478, и теперь он пробился в What New в документе Python 3.5.

Однако, поскольку многие организации все еще находятся на Python 2, вы можете сделать это в обратном режиме. Классически Pythonic путь, доступный в Python 2 и Python 3.0-3.4, заключается в том, чтобы сделать это как двухэтапный процесс:

z = x.copy()
z.update(y) # which returns None since it mutates z

В обоих подходах y будет вторым, а его значения будут заменять значения x, поэтому 'b' укажет на 3 в нашем конечном результате.

Еще не на Python 3.5, но нужно одно выражение

Если вы еще не находитесь на Python 3.5 или вам нужно написать обратный код, и вы хотите, чтобы это было в одном выражении, наиболее эффективным и правильным подходом является включение его в функцию:

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

и тогда у вас есть одно выражение:

z = merge_two_dicts(x, y)

Вы также можете создать функцию для слияния неопределенного числа dicts, от нуля до очень большого числа:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

Эта функция будет работать в Python 2 и 3 для всех dicts. например, заданный dicts a to g:

z = merge_dicts(a, b, c, d, e, f, g) 

и пары ключевых значений в g будут иметь приоритет над dicts a to f и так далее.

Критика других ответов

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

z = dict(x.items() + y.items())

В Python 2 вы создаете два списка в памяти для каждого dict, создаете третий список в памяти с длиной, равной длине первых двух вместе, а затем отбрасываете все три списка для создания dict. В Python 3 это провалится, потому что вы добавляете два объекта dict_items вместе, а не два списка -

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

и вам придется явно создавать их в виде списков, например z = dict(list(x.items()) + list(y.items())). Это пустая трата ресурсов и вычислительная мощность.

Точно так же, объединение items() в Python 3 (viewitems() в Python 2.7) также завершится неудачей, если значения являются нераспаковываемыми объектами (например, списками). Даже если ваши значения хешируются, поскольку наборы семантически неупорядочены, поведение не определено в отношении приоритета. Поэтому не делайте этого:

>>> c = dict(a.items() | b.items())

Этот пример демонстрирует, что происходит, когда значения не сотрясаются:

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Здесь пример, где y должен иметь приоритет, но вместо этого значение из x сохраняется из-за произвольного порядка множеств:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

Другой взлом не следует использовать:

z = dict(x, **y)

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

Здесь приведен пример использования, который исправляется в django.

Дикты предназначены для приема хешируемых ключей (например, фризонсет или кортежей), но этот метод не работает в Python 3, когда ключи не являются строками.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Из списка рассылки Guido van Rossum, создатель языка, написал:

Я в порядке с объявлением dict ({}, ** {1: 3}) незаконным, поскольку в конце концов это злоупотребление ** механизмом.

а также

Очевидно, dict (x, ** y) идет вокруг как "классный взлом" для "вызова x.update(y) и возврата x". Лично я считаю это более презренным, чем прохладным.

Я понимаю (а также понимание создателя языка), что предполагаемое использование dict(**y) предназначено для создания dicts для целей удобочитаемости, например:

dict(a=1, b=10, c=11)

вместо

{'a': 1, 'b': 10, 'c': 11}

Ответ на комментарии

Несмотря на то, что говорит Гвидо, dict(x, **y) соответствует спецификации dict, что кстати. работает как для Python 2, так и для 3. Тот факт, что это работает только для строковых ключей, является прямым следствием того, как работают параметры ключевого слова, а не короткого числа dict. Также не используется оператор ** в этом месте, злоупотребление механизмом, на самом деле ** было разработано именно для передачи dicts в качестве ключевых слов.

Опять же, он не работает для 3, когда ключи не являются строками. Контракт неявного вызова заключается в том, что пространства имен принимают обычные dicts, тогда как пользователи должны передавать только аргументы ключевых слов, которые являются строками. Все остальные вызовы принудительно его применяли. dict нарушил эту последовательность в Python 2:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

Эта несогласованность была плохой при других реализациях Python (Pypy, Jython, IronPython). Таким образом, он был исправлен в Python 3, так как это использование может быть изменением.

Я подчиняюсь вам, что злонамеренная некомпетентность преднамеренно пишет код, который работает только в одной версии языка или работает только с определенными произвольными ограничениями.

Еще один комментарий:

dict(x.items() + y.items()) по-прежнему является наиболее читаемым решением для Python 2. Показатели удобочитаемости.

Мой ответ: merge_two_dicts(x, y) самом деле кажется намного яснее для меня, если мы действительно обеспокоены читабельностью. И он не является совместимым с переходом, поскольку Python 2 все больше устаревает.

Менее совершенные, но правильные рекламные объявления

Эти подходы менее эффективны, но они будут обеспечивать правильное поведение. Они будут намного менее эффективными, чем copy и update или новая распаковка, потому что они перебирают каждую пару "ключ-значение" на более высоком уровне абстракции, но они уважают порядок приоритета (последние имеют приоритет)

Вы также можете связать dicts вручную внутри понимания dict:

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

или в python 2.6 (и, возможно, уже в 2.4, когда были введены выражения генератора):

dict((k, v) for d in dicts for k, v in d.items())

itertools.chain итераторы по парам ключ-значение в правильном порядке:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Анализ производительности

Я только собираюсь провести анализ эффективности известных нам правил.

import timeit

На Ubuntu 14.04 выполняется следующее:

В Python 2.7 (система Python):

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

В Python 3.5 (deadsnakes PPA):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

Ресурсы по словарям

3627
ответ дан 11 нояб. '14 в 1:11
источник

В вашем случае, что вы можете сделать, это:

z = dict(x.items() + y.items())

Это, как вы пожелаете, поместите окончательный dict в z и сделайте правильное переопределение значения для клавиши b вторым значением (y):

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Если вы используете Python 3, это немного сложнее. Чтобы создать z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
1463
ответ дан 02 сент. '08 в 10:50
источник

Альтернатива:

z = x.copy()
z.update(y)
560
ответ дан 02 сент. '08 в 16:00
источник

Другой, более сжатый вариант:

z = dict(x, **y)

Примечание: это стало популярным ответом, но важно указать, что если y имеет любые нестрочные ключи, то факт, что это работает вообще, - это злоупотребление Подробности реализации CPython, и это не работает в Python 3, или в PyPy, IronPython или Jython. Кроме того, Guido не является поклонником. Поэтому я не могу рекомендовать этот метод для переносного кода с передовой совместимостью или перекрестной реализации, что на самом деле означает, что его следует полностью исключить.

280
ответ дан 02 сент. '08 в 18:52
источник

Это, вероятно, не будет популярным ответом, но вы почти наверняка не хотите этого делать. Если вам нужна копия слияния, используйте копию (или deepcopy, в зависимости от того, что вы хотите), а затем обновите. Две строки кода намного читаемы - больше Pythonic - чем создание одной строки с помощью .items() +.items(). Явный лучше, чем неявный.

Кроме того, когда вы используете .items() (pre Python 3.0), вы создаете новый список, содержащий элементы из dict. Если ваши словари большие, то это довольно много накладных расходов (два больших списка, которые будут выброшены, как только будет создан объединенный dict). update() может работать более эффективно, потому что он может работать через второй элемент dict-by-item.

В терминах time:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO крошечное замедление между первыми двумя стоит того, чтобы читать. Кроме того, аргументы ключевых слов для создания словаря были добавлены только в Python 2.3, тогда как copy() и update() будут работать в более старых версиях.

172
ответ дан 08 сент. '08 в 14:16
источник

В последующем ответе вы спросили об относительной производительности этих двух альтернатив:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

На моей машине, по крайней мере (довольно обычный x86_64, работающий с Python 2.5.2), альтернативный z2 не только короче и проще, но и значительно быстрее. Вы можете проверить это самостоятельно, используя модуль timeit, который поставляется с Python.

Пример 1: идентичные словари, отображающие 20 последовательных целых чисел:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z2 выигрывает в 3,5 раза или около того. Кажется, что разные словари дают совершенно разные результаты, но z2 всегда, кажется, выходит вперед. (Если вы получите несогласованные результаты для одного и того же теста, попробуйте перейти в -r с номером, большим, чем значение по умолчанию.)

Пример 2: неперекрывающиеся словари, отображающие 252 коротких строк для целых чисел и наоборот:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 выигрывает примерно в 10 раз. Это довольно большая победа в моей книге!

После сравнения этих двух, я задавался вопросом, может ли z1 низкая производительность быть связана с накладными расходами на создание двух списков элементов, что в свою очередь побудило меня задаться вопросом, может ли это изменение работать лучше:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

Несколько быстрых тестов, например

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

привести меня к выводу, что z3 несколько быстрее, чем z1, но не так быстро, как z2. Определенно не стоит все лишнее набирать текст.

В этом обсуждении по-прежнему отсутствует что-то важное, что сравнивает производительность этих альтернатив с "очевидным" способом слияния двух списков: с помощью метода update. Чтобы попытаться удержать вещи на равных с выражениями, ни один из которых не изменит x или y, я собираюсь сделать копию x вместо ее изменения на месте следующим образом:

z0 = dict(x)
z0.update(y)

Типичный результат:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

Другими словами, z0 и z2 кажутся практически одинаковыми. Считаете ли вы, что это может быть совпадением? Я не...

Фактически, я бы зашел так далеко, чтобы утверждать, что невозможно, чтобы чистый код Python делал что-то лучше этого. И если вы можете сделать значительно лучше в модуле расширения C, я думаю, что люди Python вполне могут заинтересоваться включением вашего кода (или вариации вашего подхода) в ядро ​​Python. Python использует dict во многих местах; оптимизация его операций - это большая сделка.

Вы также можете написать это как

z0 = x.copy()
z0.update(y)

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

119
ответ дан 23 окт. '08 в 5:38
источник

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

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result
87
ответ дан 04 сент. '08 в 22:08
источник

В Python 3 вы можете использовать collections.ChainMap, который объединяет несколько диктов или других сопоставлений для создания единого обновляемого представления:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11
78
ответ дан 28 апр. '13 в 6:15
источник

Рекурсивно/глубокое обновление dict

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

Демонстрация:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

Выходы:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

Спасибо rednaw за изменения.

62
ответ дан 29 нояб. '11 в 14:52
источник

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

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

Это быстрее, чем dict(x.items() + y.items()), но не так быстро, как n = copy(a); n.update(b), по крайней мере, на CPython. Эта версия также работает в Python 3, если вы меняете iteritems() на items(), что автоматически выполняется с помощью инструмента 2to3.

Лично мне нравится эта версия лучше всего, потому что она описывает довольно хорошую, что я хочу, в одном функциональном синтаксисе. Единственная незначительная проблема заключается в том, что совершенно не очевидно, что значения из y имеют приоритет над значениями из x, но я не считаю, что это трудно понять.

55
ответ дан 14 окт. '10 в 21:55
источник

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}
45
ответ дан 27 февр. '15 в 0:27
источник
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

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

42
ответ дан 02 сент. '08 в 10:49
источник

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

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

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

37
ответ дан 14 окт. '11 в 19:12
источник
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'}
35
ответ дан 06 авг. '12 в 12:24
источник

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

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}

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

27
ответ дан 23 нояб. '11 в 21:08
источник

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

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

>>> print z
{'a': 1, 'c': 11, 'b': 10}
22
ответ дан 20 янв. '16 в 14:46
источник

В 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 не являются строками.

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

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

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

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, но выглядит менее практичным, где может быть много поисков.

21
ответ дан 09 окт. '13 в 21:09
источник

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

>>> 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}
16
ответ дан 08 авг. '13 в 0:23
источник

Простое решение с использованием 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}
15
ответ дан 04 авг. '15 в 17:54
источник

Два словаря

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/

13
ответ дан 17 окт. '12 в 5:09
источник

В python 3:

import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}

r = dict(collections.ChainMap(a, b, c))
print(r)

Из:

{1: 1, 2: 2, 3: 4}

Документы: https://docs.python.org/3/library/collections.html#collections.ChainMap:

13
ответ дан 24 мая '17 в 10:24
источник

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

Примеры:

a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())

Ожидалось бы что-то вроде этого:

{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }

Вместо этого получим следующее:

{'two': True, 'one': {'extra': False}}

В "одной" записи должны были быть "depth_2" и "дополнительные" как элементы внутри словаря, если это действительно было слияние.

Использование цепочки также не работает:

from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

Результаты в:

{'two': True, 'one': {'extra': False}}

Глубокое слияние, которое дал rcwesick, также создает тот же результат.

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

11
ответ дан 04 авг. '12 в 2:36
источник

Для Python 2:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()+y.items())
print(z)

Для Python 3:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()|y.items())
print(z)

Он выводит результат: {'a': 1, 'c': 11, 'b': 10}

10
ответ дан 31 авг. '16 в 16:53
источник

Опираясь на идеи здесь и в других местах, я понял функцию:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Использование (проверено на python 3):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

Вместо этого вы можете использовать лямбда.

8
ответ дан 19 июля '13 в 8:49
источник

В Python 3.5 вы можете использовать unpack ** для создания нового словаря. Этот метод не был показан в прошлых ответах. Кроме того, лучше использовать {} вместо dict(). Поскольку {} - это литерал python, а dict() - вызов функции.

dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}
6
ответ дан 28 сент. '16 в 3:33
источник

Для этого вы можете использовать toolz.merge([x, y]).

6
ответ дан 18 нояб. '16 в 15:53
источник
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

Это должно решить вашу проблему.

6
ответ дан 30 нояб. '15 в 16:04
источник

Проблема, которую я имею с решениями, перечисленными на сегодняшний день, заключается в том, что в объединенном словаре значение для ключа "b" равно 10, но, к моему мышлению, это должно быть 12. В этом свете я представляю следующее:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

Результаты:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}
6
ответ дан 03 дек. '13 в 21:11
источник
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}
6
ответ дан 13 нояб. '13 в 13:01
источник

Это можно сделать с помощью единственного понимания:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

На мой взгляд, лучший ответ для части "одного выражения" как дополнительных функций не требуется, и он короток.

6
ответ дан 17 июля '15 в 17:47
источник
  • 1
  • 2

Другие вопросы по меткам или Задайте вопрос