Como mesclar dois dicionários em uma única expressão?

votos
3k

Eu tenho dois dicionários Python, e eu quero escrever uma única expressão que retorna esses dois dicionários, mescladas. O update()método seria o que eu preciso, se ele voltou seu resultado em vez de modificar um dicionário no local.

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

Como posso obter esse dict mesclado final z, não x?

(Para ser extra-claro, o último-um-ganha conflito de manipulação de dict.update()é o que eu estou procurando também.)

Publicado 02/09/2008 em 08:44
fonte usuário
Em outras línguas...                            


56 respostas

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

Para os itens com chaves em ambos os dicionários ( 'b'), você pode controlar quais um acaba na saída, colocando que uma última.

Respondeu 02/09/2008 em 08:49
fonte usuário

votos
1k

No seu caso, o que você pode fazer é:

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

Esta vontade, como você quiser, colocar o dict final z, e fazer o valor para a chave bser devidamente substituído pelo segundo ( yvalor de dict):

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

Se você usar o Python 3, é apenas um pouco mais complicado. Para criar z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
Respondeu 02/09/2008 em 08:50
fonte usuário

votos
542

Uma alternativa:

z = x.copy()
z.update(y)
Respondeu 02/09/2008 em 14:00
fonte usuário

votos
269

Outra, mais conciso, opção:

z = dict(x, **y)

Nota : este tornou-se uma resposta popular, mas é importante ressaltar que, se ytem todas as chaves não-corda, o fato de que isso funciona em tudo é um abuso de detalhe de implementação CPython, e ele não funciona em Python 3, ou em PyPy, IronPython, ou Jython. Além disso, Guido não é um fã . Então, eu não posso recomendar esta técnica para o código portátil de implementação cruz frente-compatível ou, o que realmente significa que ele deve ser totalmente evitada.

Respondeu 02/09/2008 em 16:52
fonte usuário

votos
85

Eu queria algo semelhante, mas com a capacidade de especificar como os valores em chaves duplicadas foram fundidas, então eu hackeado isso (mas não muito testá-lo). Obviamente, isso não é uma única expressão, mas é uma única chamada de função.

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
Respondeu 04/09/2008 em 20:08
fonte usuário

votos
165

Este provavelmente não será uma resposta popular, mas você quase certamente não quero fazer isso. Se você quiser uma cópia que é uma junção, então usar cópia (ou deepcopy , dependendo do que você quiser) e depois atualizar. As duas linhas de código são muito mais legível - mais Pythonic - do que a criação de linha única com .items () + .items (). Explícito é melhor que implícito.

Além disso, quando você usa .items () (pré Python 3.0), você está criando uma nova lista que contém os itens do dict. Se os seus dicionários são grandes, então isso é bastante gerais (duas grandes listas que vai ser jogado fora assim que o dict mesclado é criado). update () pode funcionar de forma mais eficiente, porque ele pode ser executado através do segundo dict item por item.

Em termos de tempo :

>>> 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 a pequena desaceleração entre os dois primeiros vale a pena para a legibilidade. Além disso, os argumentos de palavra-chave para a criação de dicionário só foi adicionada no Python 2.3, enquanto copiar () e update () irá funcionar em versões mais antigas.

Respondeu 08/09/2008 em 12:16
fonte usuário

votos
114

Em uma resposta follow-up, você perguntou sobre o desempenho relativo destas duas alternativas:

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

Na minha máquina, pelo menos (a x86_64 execução Python bastante