Question

J'ai deux dictionnaires Python, et je veux écrire une seule expression qui renvoie ces deux dictionnaires, ont fusionné.L' update() méthode pourrait être ce dont j'ai besoin, si il est rentré de son résultat au lieu de modifier un dict en place.

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

Comment puis-je obtenir fusionné final dict en z, pas x?

(Pour être plus clair, la dernière-et-un-victoires de gestion des conflits d' dict.update() est ce que je suis à la recherche aussi bien.)

Était-ce utile?

La solution

Comment puis-je fusionner les deux dictionnaires Python dans une expression unique?

Pour les dictionnaires x et y, z devient un superficiellement fusionné dictionnaire avec des valeurs de y remplacement de ceux de x.

  • En Python de 3,5 ou plus:

    z = {**x, **y}
    
  • En Python 2, (3,4 ou moins) écrire une fonction:

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

    et maintenant:

    z = merge_two_dicts(x, y)
    

Explication

Disons que vous avez deux dicts et vous souhaitez les fusionner dans un nouveau dict sans altérer l'original dicts:

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

Le résultat souhaité est d'obtenir un nouveau dictionnaire (z) avec les valeurs fusionnées, et la deuxième dict valeurs d'écraser ceux de la première.

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

Une nouvelle syntaxe pour ce, qui est proposé dans PEP 448 et disponibles en Python 3.5, est

z = {**x, **y}

Et c'est en effet une expression unique.

Notez que nous pouvons fusionner avec littéral de la notation ainsi:

z = {**x, 'foo': 1, 'bar': 2, **y}

et maintenant:

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

Il est maintenant mis en œuvre dans le calendrier de sortie de 3,5, PEP 478, et il a maintenant fait son chemin dans Ce qui est Nouveau en Python 3.5 document.

Cependant, comme beaucoup d'organisations sont encore sur Python 2, vous pouvez le faire dans un rétro-compatible façon.Le classique Pythonic façon, disponible en Python 2 et Python 3.0-3.4, est de le faire comme un processus en deux étapes:

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

Dans les deux approches, y viendra deuxième et de ses valeurs remplacera x's des valeurs, de ce 'b' pointeront à 3 dans notre résultat final.

Pas encore sur Python 3.5, mais que vous voulez un expression unique

Si vous n'êtes pas encore sur Python 3.5, ou le besoin d'écrire vers l'arrière-compatible code, et vous voulez que ce dans un expression unique, la plus performante, tandis que la bonne approche est de le mettre dans une fonction:

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

et puis vous avez une seule expression:

z = merge_two_dicts(x, y)

Vous pouvez également faire une fonction pour fusionner un nombre indéterminé de dicts, de zéro à un très grand nombre:

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

Cette fonction fonctionne en Python 2 et 3 pour tous les dicts.par exempleétant donné dicts a pour g:

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

et des paires clé-valeur dans g aura préséance sur dicts a pour f, et ainsi de suite.

Les Critiques des Autres Réponses

N'utilisez pas ce que vous voyez dans l'ancien accepté de répondre:

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

En Python 2, vous créez deux listes en mémoire pour chaque dict, d'en créer une troisième liste dans la mémoire avec une longueur égale à la longueur de la première de deux mis ensemble, puis les jeter tous les trois listes pour créer le dict. En Python 3, on va à l'échec parce que vous êtes à l'ajout de deux dict_items ensemble des objets, pas deux listes -

>>> 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'

vous devez créer explicitement sous forme de listes, par exemple z = dict(list(x.items()) + list(y.items())).C'est un gaspillage de ressources et de puissance de calcul.

De même, l'union des items() en Python 3 (viewitems() en Python 2.7) échouera également lorsque les valeurs sont unhashable des objets (comme des listes, par exemple).Même si vos valeurs sont hashable, depuis, les ensembles sont sémantiquement non ordonnée, le comportement est indéfini en ce qui concerne la priorité.Donc, ne pas faire ceci:

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

Cet exemple montre ce qui arrive quand les valeurs sont unhashable:

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

Voici un exemple où y devrait avoir la priorité, mais plutôt la valeur de x est retenu en raison de l'ordre arbitraire de jeux:

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

Un autre hack vous ne devez pas utiliser:

z = dict(x, **y)

Il utilise le dict constructeur, et est très rapide et très efficace en terme de mémoire (même un peu plus-que nos processus en deux étapes), mais à moins de savoir précisément ce qui se passe ici (c'est la deuxième dict est passé comme mot-clé arguments à la dict constructeur), c'est difficile à lire, ce n'est pas l'usage prévu, et donc il n'est pas Pythonic.

Voici un exemple de l'utilisation restauré dans django.

Dicts sont destinés à prendre hashable clés (p. ex.frozensets ou tuples), mais cette méthode échoue en Python 3 lorsque les touches ne sont pas des chaînes.

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

À partir de la liste de diffusion, Guido van Rossum, le créateur de la langue, a écrit:

Je suis très bien avec déclarant dict({}, **{1:3}) illégal, car après tout, c'est de l'abus de l' ** mécanisme.

et

Apparemment dict(x, **y) va autour comme "cool hack" pour "call x.mise à jour(y) et retour x".Personnellement, je la trouve de plus détestable que cool.

C'est ma compréhension (ainsi que la compréhension de la créateur de la langue) que l'utilisation prévue pour dict(**y) pour créer des dicts pour des raisons de lisibilité, par exemple:

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

au lieu de

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

Réponse aux commentaires

En dépit de ce que dit Guido, dict(x, **y) est en ligne avec le dict cahier des charges, qui btw.fonctionne pour Python 2 et 3.Le fait que cela ne fonctionne que pour les clés de chaîne est une conséquence directe de la façon dont le mot clé des paramètres de travail et non pas un court-venant de dict.Ni est l'aide de l'opérateur ** en ce lieu un abus du mécanisme, en fait ** a été conçu précisément pour passer dicts comme mots-clés.

Encore une fois, il ne fonctionne pas pour 3 lorsque les clés sont non-chaînes.L'implicite de l'appel de contrat est que les espaces de noms ordinaire dicts, tandis que les utilisateurs doivent seulement mot-clé pass arguments qui sont des chaînes de caractères.Tous les autres callables mettre à exécution. dict a brisé cette cohérence en 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}

Cette incohérence a été mauvais étant donné que d'autres implémentations de Python (Pypy, Jython, IronPython).Ainsi, il a été fixé en Python 3, que cette utilisation soit d'une modification de rupture.

Je vous assure qu'il est malveillant incompétence volontaire d'écrire du code qui ne fonctionne que dans une version d'une langue ou qui ne fonctionne que compte tenu de certaines contraintes arbitraires.

Plus de commentaires:

dict(x.items() + y.items()) c'est toujours la plus lisible solution pour Python 2.La lisibilité des comptes.

Ma réponse: merge_two_dicts(x, y) en réalité semble beaucoup plus clair pour moi, si nous sommes vraiment préoccupés au sujet de la lisibilité.Et il n'est pas compatible, que Python 2 est de plus en plus obsolète.

{**x, **y} ne semble pas gérer imbriqués les dictionnaires.le contenu des clés imbriquées sont tout simplement écrasé, pas fusionné [...] j'ai été brûlés par ces réponses qui ne fusionnent pas de manière récursive et j'ai été surpris personne mentionnée.Dans mon interprétation du mot "fusion" de ces réponses décrire "mise à jour d'un dictionnaire à un autre", et non pas la fusion.

Oui.Je vous renvoie la question, qui demande un peu profonde fusion de deux dictionnaires, avec la première des valeurs écrasée par la seconde - dans une expression unique.

En supposant que les deux dictionnaire des dictionnaires, on peut de manière récursive les fusionner en une seule fonction, mais vous devez être prudent de ne pas modifier les dicts de la source, et le plus sûr moyen d'éviter cette situation est de faire une copie lors de l'affectation de valeurs.Que les clés doivent être hashable et sont généralement donc immuable, et il est inutile de les copier:

from copy import deepcopy

def dict_of_dicts_merge(x, y):
    z = {}
    overlapping_keys = x.keys() & y.keys()
    for key in overlapping_keys:
        z[key] = dict_of_dicts_merge(x[key], y[key])
    for key in x.keys() - overlapping_keys:
        z[key] = deepcopy(x[key])
    for key in y.keys() - overlapping_keys:
        z[key] = deepcopy(y[key])
    return z

Utilisation:

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

Venir avec des éventualités pour d'autres types de valeur est bien au-delà de la portée de cette question, donc je vais vous au ma réponse à la canonique question sur un "Dictionnaires les dictionnaires de fusion".

Moins Performant, Mais bon Ad-hocs

Ces approches sont moins performants, mais ils fourniront comportement correct.Ils seront beaucoup moins performantes qu' copy et update ou le nouveau déballage parce qu'ils itérer sur chaque paire clé-valeur à un niveau d'abstraction plus élevé, mais ils faire respecter l'ordre de préséance (dernier dicts ont priorité)

Vous pouvez également la chaîne les dicts manuellement à l'intérieur d'un dict compréhension:

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

ou dans la version 2.6 de python (et peut-être dès 2.4 lorsque le générateur d'expressions ont été introduits):

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

itertools.chain aura de la chaîne d'itérateurs sur les paires clé-valeur dans le bon ordre:

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

Analyse De La Performance

Je suis seulement de faire de l'analyse de la performance des usages connu pour se comporter correctement.

import timeit

La suite se fait sur Ubuntu 14.04

En Python 2.7 (système de 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

En 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

Ressources sur les Dictionnaires

Autres conseils

Dans votre cas, ce que vous pouvez faire est:

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

Ce sera, comme vous le voulez, mettre la dernière dict en z, et la valeur de la clé b être correctement remplacée par la deuxième (y) dict de la valeur:

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

Si vous utilisez Python 3, il est seulement un peu plus compliqué.Pour créer z:

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

Une alternative:

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

Un autre, plus concis, option:

z = dict(x, **y)

Note:c'est devenu un populaire réponse, mais il est important de souligner que, si y a tout non-clés de chaîne, le fait que cela fonctionne à tous est un abus de Disponible détail d'implémentation, et il ne fonctionne pas en Python 3, ou dans PyPy, IronPython, ou Jython.Aussi, Guido n'est pas un fan.Donc je ne peux pas recommander cette technique pour compatible ou de la croix-de la mise en œuvre du code portable, ce qui signifie qu'il doit être entièrement évité.

Ce ne sera probablement pas une réponse, mais vous avez presque certainement ne voulez pas le faire.Si vous voulez une copie d'une fusion, puis utiliser la copie (ou propriétédeepcopy, selon ce que vous voulez), puis mise à jour.Les deux lignes de code beaucoup plus lisible plus Pythonic - de la création de la ligne à .les éléments() + .les éléments().Explicite est mieux qu'implicites.

En outre, lorsque vous utilisez .les éléments() (pré Python 3.0), vous êtes en train de créer une nouvelle liste qui contient les éléments de la dict.Si votre dictionnaires sont grandes, alors que c'est beaucoup de frais généraux (deux grandes listes qui seront jetés dès que la fusion dict est créé).mise à jour() peuvent travailler plus efficacement, car il peut courir à travers la deuxième dict de l'élément par élément.

En termes de le temps:

>>> 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 le petit ralentissement entre les deux premiers est-il la peine pour la lisibilité.En outre, les arguments mots-clefs pour créer un dictionnaire n'a été ajouté en Python 2.3, tandis que la copie() et update() va travailler dans les anciennes versions.

Dans un suivi de la réponse, vous avez demandé à propos de la performance relative de ces deux alternatives:

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

Sur ma machine, au moins assez ordinaire x86_64 lancer Python 2.5.2), d'autres z2 n'est pas seulement plus rapide et plus simple, mais aussi beaucoup plus rapide.Vous pouvez le vérifier par vous-même à l'aide de la timeit module livré avec Python.

Exemple 1:identique dictionnaires cartographie 20 nombres entiers consécutifs à eux-mêmes:

% 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 victoires par un facteur de 3,5 ou plus.Les différents dictionnaires paraît donner des résultats assez différents, mais z2 semble toujours aller de l'avant.(Si vous obtenez des résultats incohérents pour le même test, essayer de passer en -r avec un nombre plus grand que la valeur par défaut de 3.)

Exemple 2:non-cumul des dictionnaires de cartographie 252 chaînes courtes pour les entiers et vice-versa:

% 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 victoires par un facteur d'environ 10.C'est une assez grande victoire, dans mon livre!

Après avoir comparé ces deux, je me demandais si z1's mauvaise performance pourrait être attribuée à la surcharge de construction de deux listes d'objets, qui à son tour m'a conduit à me demander si cette variation pourrait fonctionner mieux:

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

Quelques tests rapides, par exemple

% 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

m'amènent à conclure que z3 est un peu plus rapide que z1, que , mais pas aussi vite que z2.Certainement pas la peine tout le taper.

Cette discussion est toujours manquer quelque chose d'important, qui est une comparaison des performances de ces solutions de rechange avec le "évident" voie de la fusion de deux listes:à l'aide de la update la méthode.Pour essayer de garder les choses sur un pied d'égalité avec les expressions, aucune de modifier x ou y, je vais faire une copie de x au lieu de le modifier sur place, comme suit:

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

Un résultat typique:

% 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

En d'autres termes, z0 et z2 semblent avoir essentiellement des performances identiques.Pensez-vous que cela pourrait être une coïncidence?Je n'ai pas....

En fait, j'irais même jusqu'à prétendre qu'il est impossible pour un pur code Python pour faire mieux que cela.Et si vous pouvez faire nettement mieux dans un C module d'extension, j'imagine que le Python de gens pourrait bien être intéressé par l'incorporation de votre code (ou une variation sur votre approche) dans le Python de base.Python utilise dict dans beaucoup d'endroits;l'optimisation de ses opérations est une grosse affaire.

Vous pouvez également écrire ce que

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

comme Tony, mais (sans surprise) la différence de notation s'avère n'avoir aucun effet mesurable sur la performance.Utilisation selon la regarde droit pour vous.Bien sûr, il a tout à fait raison de souligner que les deux-déclaration de version est beaucoup plus facile à comprendre.

Je voulais quelque chose de similaire, mais avec la possibilité de spécifier comment les valeurs sur des doubles de clés ont été fusionnés, j'ai piraté ceci (mais n'a pas fortement de le tester).Évidemment, ce n'est pas une simple expression, mais c'est un seul appel de fonction.

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

En Python 3, vous pouvez utiliser les collections.ChainMap qui regroupe plusieurs dicts ou d'autres mappages ensemble pour créer une seule, mise à jour de la vue:

>>> 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

De manière récursive/deep mise à jour d'un dict

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's 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

Démonstration:

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

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

print deepupdate(pluto_original, pluto_update)

Sorties:

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

Grâce rednaw pour les modifications.

La meilleure version que je pouvais penser lorsque vous n'utilisez pas de copie serait:

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

Il est plus rapide que dict(x.items() + y.items()) mais pas aussi vite que n = copy(a); n.update(b), au moins sur Disponible.Cette version fonctionne aussi en Python 3 en cas de changement iteritems() pour items(), qui est fait automatiquement par l'2to3 outil.

Personnellement, j'aime cette version meilleure, parce qu'elle décrit assez bien ce que je veux dans un seul syntaxe fonctionnelle.Le seul petit problème est que ça ne fait pas tout à fait évident que les valeurs de y a priorité sur les valeurs de x, mais je ne crois pas que c'est difficile de comprendre cela.

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

Pour les objets avec des touches dans les deux dictionnaires ('b'), vous pouvez contrôler qui finit dans la sortie en mettre une dernière.

Python 3.5 (PEP 448) permet une meilleure syntaxe de l'option:

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

Ou même

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

Alors que la question a déjà été répondu plusieurs fois, cette solution simple à ce problème n'a pas été encore inscrit.

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

Il est aussi rapide que z0 et le mal z2 mentionné ci-dessus, mais facile à comprendre et à modifier.

def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Parmi ces ombragé et douteux réponses, ce brillant exemple est le seul et unique bon moyen de fusionner les dicts en Python, approuvé par le dictateur pour la vie Guido van Rossum lui-même!Quelqu'un d'autre a suggéré la moitié de cette, mais ne pas le mettre dans une fonction.

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

donne:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

Si vous pensez que les lambdas sont mal alors lisez pas plus loin.Sur demande, vous pouvez écrire à la fois rapide et efficace de la mémoire de la solution avec une expression:

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}

Comme suggéré ci-dessus, à l'aide de deux lignes ou l'écriture d'une fonction est probablement une meilleure façon d'aller.

Être pythonic.L'utilisation d'un la compréhension:

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

>>> print z
{'a': 1, 'c': 11, 'b': 10}

En python3, l' items méthode ne renvoie plus à une liste, mais plutôt un vue, qui agit comme un ensemble.Dans ce cas, vous aurez besoin de prendre l'ensemble de l'union depuis la concaténation avec + ne fonctionne pas:

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

Pour python3-comme le comportement de la version 2.7, l' viewitems méthode de travail en lieu et place de items:

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

Je préfère cette notation, de toute façon, puisqu'il semble plus naturel de penser que c'est un jeu de fonctionnement de l'union plutôt que de concaténation (comme le titre l'indique).

Edit:

Un couple plus de points pour python 3.Tout d'abord, notez que l' dict(x, **y) astuce ne fonctionne pas en python 3, à moins que les clés dans y sont des chaînes de caractères.

Aussi, Raymond Hettinger de Chainmap réponse est assez élégant, car il peut prendre un nombre arbitraire de dicts comme arguments, mais à partir de la documentation on dirait qu'il séquentiellement regarde à travers une liste de tous les dicts pour chaque recherche:

Les recherches de recherche sous-jacentes mappages successivement jusqu'à ce qu'une touche est trouvée.

Cela peut vous ralentir si vous avez beaucoup de recherches dans votre application:

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

Donc environ un ordre de grandeur plus lent pour les recherches.Je suis un fan de Chainmap, mais semble moins pratique où il peut y avoir de nombreuses recherches.

Abus conduisant à une expression de la solution pour La réponse de matthieu:

>>> 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}

Vous avez dit que vous vouliez une expression, donc j'ai abusé lambda pour lier un nom, et les tuples pour remplacer lambda est une expression de la limite.Hésitez pas à grincer des dents.

Vous pourriez aussi le faire bien sûr, si vous n'avez pas de soins sur la copie:

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

Solution Simple à l'aide de itertools qui préserve l'ordre (ci dicts ont priorité)

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

Et son utilisation:

>>> 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}

Deux dictionnaires

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

n dictionnaires

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

sum a la mauvaise performance.Voir https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

Même si les réponses ont été bonnes pour ce peu profonde dictionnaire, aucune des méthodes définies ici réellement faire une profonde dictionnaire de fusion.

Exemples:

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

On pourrait attendre d'une suite à quelque chose comme ceci:

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

Au lieu de cela, nous obtenons ceci:

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

La " une "entrée doit avoir eu "depth_2" et "extra", comme des éléments à l'intérieur de son dictionnaire si c'était vraiment une fusion.

L'aide d'une chaîne aussi, ne fonctionne pas:

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

Résultats:

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

La profondeur de fusion qui rcwesick a également crée le même résultat.

Oui, il va travailler à la fusion de l'échantillon des dictionnaires, mais aucun d'entre eux sont un mécanisme générique pour fusionner.Je vais mettre à jour plus tard une fois que j'écris une méthode qui ne un vrai de fusion.

Dessin sur les idées d'ici et d'ailleurs j'ai compris une fonction:

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

Utilisation (testé en 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})

Vous pouvez utiliser une lambda à la place.

Le problème que j'ai avec les solutions répertoriées à ce jour, c'est que, dans la fusion de dictionnaire, la valeur de la clé "b" est de 10, mais à ma façon de penser, il doit être de 12.A la lumière de cela, je vous présente le suivant:

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

Résultats:

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}
>>> 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}

Cela peut être fait avec un seul dict compréhension:

>>> 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)
    }

À mon avis, la meilleure réponse pour la 'simple' expression " partie pas de fonctions supplémentaires sont nécessaires, et il est court.

from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

Cela devrait résoudre votre problème.

(Pour Python2.7* seulement;il y a des solutions plus simples pour Python3*.)

Si vous n'êtes pas opposés à l'importation d'une bibliothèque standard du module, vous pouvez le faire

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

(Le or a peu dans l' lambda est nécessaire parce que dict.update retourne toujours None en cas de succès.)

C'est tellement idiot que .update renvoie rien.
Je viens d'utiliser une simple fonction d'assistance à résoudre le problème:

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

Exemples:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy

À l'aide d'un dict compréhension, vous pouvez

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

dc = {xi:(x[xi] if xi not in list(y.keys()) 
           else y[xi]) for xi in list(x.keys())+(list(y.keys()))}

donne

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

Notez que la syntaxe pour if else dans la compréhension

{ (some_key if condition else default_key):(something_if_true if condition 
          else something_if_false) for key, value in dict_.items() }

Je sais que ce n'est pas vraiment adaptés à la spécificité des questions ("one liner"), mais depuis aucun les réponses ci-dessus sont allés dans cette direction tandis que beaucoup, beaucoup de réponses abordé le problème de performances, j'ai senti que je devrait contribuer de mes pensées.

Selon le cas d'utilisation, il peut ne pas être nécessaire de créer un "vrai" fusionné dictionnaire de la donnée d'entrée des dictionnaires.Un vue qui ne ce peut être suffisante dans la plupart des cas, je.e.un objet qui agit comme la fusion de dictionnaire serait sans calcul complètement.Un paresseux version de la fusion de dictionnaire, pour ainsi dire.

En Python, c'est assez simple et peut être fait avec le code indiqué à la fin de mon post.Dans ce cas, la réponse à la question d'origine serait:

z = MergeDict(x, y)

Lors de l'utilisation de ce nouvel objet, il va se comporter comme une fusion de dictionnaire, mais il aura constante de temps de création et de la constante de mémoire, tout en laissant l'original dictionnaires intacte.La création c'est beaucoup moins cher que dans les autres solutions proposées.

Bien sûr, si vous utilisez le résultat de beaucoup de choses, alors vous allez à un certain point d'atteindre la limite où la création d'un véritable fusionné dictionnaire aurait été la solution plus rapide.Comme je l'ai dit, cela dépend de votre cas d'utilisation.

Si vous jamais senti que vous préférez avoir un réel fusionné dict, puis de l'appel d' dict(z) serait produire (mais de façon plus coûteux que les autres solutions, bien sûr, donc c'est juste la peine de mentionner).

Vous pouvez également utiliser cette classe pour en faire une sorte de copie sur écriture dictionnaire:

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

Voici le straight-forward code de MergeDict:

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top