d3 = dict(d1, **d2)
Eu entendo que isso mescla o dicionário. Mas, é único? E se d1 tiver a mesma chave que d2, mas um valor diferente? Gostaria que d1 e d2 fossem mesclados, mas d1 tem prioridade se houver chave duplicada.
d3 = dict(d1, **d2)
Eu entendo que isso mescla o dicionário. Mas, é único? E se d1 tiver a mesma chave que d2, mas um valor diferente? Gostaria que d1 e d2 fossem mesclados, mas d1 tem prioridade se houver chave duplicada.
Respostas:
Você pode usar o .update()
método se não precisar mais do original d2
:
Atualize o dicionário com os pares de chave / valor de outro, sobrescrevendo as chaves existentes . Retorno
None
.
Por exemplo:
>>> d1 = {'a': 1, 'b': 2}
>>> d2 = {'b': 1, 'c': 3}
>>> d2.update(d1)
>>> d2
{'a': 1, 'c': 3, 'b': 2}
Atualizar:
Claro que você pode copiar o dicionário primeiro para criar um novo mesclado. Isso pode ou não ser necessário. Caso você tenha objetos compostos (objetos que contêm outros objetos, como listas ou instâncias de classe) em seu dicionário, copy.deepcopy
também deve ser considerado.
isinstance(int, object) is True
ainda deepcopy
não parece necessário.
Em Python2,
d1={'a':1,'b':2}
d2={'a':10,'c':3}
d1 substitui d2:
dict(d2,**d1)
# {'a': 1, 'c': 3, 'b': 2}
d2 substitui d1:
dict(d1,**d2)
# {'a': 10, 'c': 3, 'b': 2}
Esse comportamento não é apenas um acaso de implementação; é garantido na documentação :
Se uma chave for especificada no argumento posicional e como um argumento de palavra-chave, o valor associado à palavra-chave será retido no dicionário.
**
notação, todas as chaves desse dict devem ser strings. Consulte o thread python-dev começando em mail.python.org/pipermail/python-dev/2010-April/099427.html para mais.
d = dict(**d1, **d2)
funciona, mas é o que @IoannisFilippidis faz referência em seu comentário. Talvez incluir o snippet aqui fosse mais claro, então aqui está.
Minha solução é definir uma função de mesclagem . Não é sofisticado e custa apenas uma linha. Aqui está o código em Python 3.
from functools import reduce
from operator import or_
def merge(*dicts):
return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }
Testes
>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d, d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d_letters, d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> merge(d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge()
{}
Ele funciona para um número arbitrário de argumentos do dicionário. Se houver alguma chave duplicada nesse dicionário, a chave do dicionário mais à direita na lista de argumentos vence.
.update
chamada nele ( merged={}
seguido por for d in dict: merged.update(d)
) seria mais curto, mais legível e mais eficiente.
reduce
e lambda
é, como sobre return reduce(lambda x, y: x.update(y) or x, dicts, {})
?
Trey Hunner tem uma boa postagem no blog que descreve várias opções para mesclar vários dicionários, incluindo (para python3.3 +) ChainMap e descompactação de dicionário .
Começando em Python 3.9
, o operador |
cria um novo dicionário com as chaves e valores mesclados de dois dicionários:
# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}
Este:
Cria um novo dicionário d3 com as chaves e valores mesclados de d2 e d1. Os valores de d1 têm prioridade quando d2 e d1 compartilham chaves.
Observe também o |=
operador que modifica d2 mesclando d1 em, com prioridade nos valores d1:
# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}
Acredito que, conforme dito acima, usar d2.update(d1)
é a melhor abordagem e que você também pode copiar d2
primeiro se ainda precisar.
Embora eu queira ressaltar que, dict(d1, **d2)
na verdade, é uma maneira ruim de mesclar dicionários em geral, já que os argumentos de palavra-chave precisam ser strings, portanto, falhará se você tiver um dict
, como:
{
1: 'foo',
2: 'bar'
}
**
passagem de argumento de palavra-chave, a menos que todas as chaves ded2
sejam strings. Se nem todas as chavesd2
são strings, isso falha no Python 3.2 e em implementações alternativas de Python como Jython, IronPython e PyPy. Consulte, por exemplo, mail.python.org/pipermail/python-dev/2010-April/099459.html .