Comment fusionner une liste de dictés en un seul dict?

124

Comment puis-je tourner une liste de dictionnaires comme celui-ci

[{'a':1}, {'b':2}, {'c':1}, {'d':2}]

En un seul dict comme celui-ci

{'a':1, 'b':2, 'c':1, 'd':2}
tuer
la source
C'est vrai, bien que cela se fond dans un dict de listes.
Katriel
1
c'est une liste et non un dict: >>> type ([{'a': 1}, {'b': 2}]) <type 'list'>
killown
Il devrait vraiment y avoir une seule ligne pour cela compte tenu de la fréquence à laquelle cela se produit. Y a-t-il une raison pour laquelle {** d pour d dans d_list} n'est pas pris en charge?
markemus le

Réponses:

164

Cela fonctionne pour les dictionnaires de toute longueur:

>>> result = {}
>>> for d in L:
...    result.update(d)
... 
>>> result
{'a':1,'c':1,'b':2,'d':2}

En guise de compréhension :

# Python >= 2.7
{k: v for d in L for k, v in d.items()}

# Python < 2.7
dict(pair for d in L for pair in d.items())
wim
la source
6
>>> L=[{'a': 1}, {'b': 2}, {'c': 1}, {'d': 2}]    
>>> dict(i.items()[0] for i in L)
{'a': 1, 'c': 1, 'b': 2, 'd': 2}

Remarque: l'ordre de 'b' et 'c' ne correspond pas à votre sortie car les dictionnaires ne sont pas ordonnés

si les dictats peuvent avoir plus d'une clé / valeur

>>> dict(j for i in L for j in i.items())
John La Rooy
la source
Échoue si l'un des dictionnaires de la liste contient plus d'un élément.
PaulMcG
2
toux * (en supposant que chaque dictionnaire ne contient qu'une seule paire valeur / clé) * toux
Katriel
Ah, eh bien j'ai d'abord posté une méthode qui fonctionne avec des dictionnaires généraux, mais il semblait que l'OP n'en avait pas besoin
John La Rooy
5

Pour les dictionnaires plats, vous pouvez le faire:

from functools import reduce
reduce(lambda a, b: dict(a, **b), list_of_dicts)
régime bouddha
la source
4

Ceci est similaire à @delnan mais offre la possibilité de modifier les éléments k / v (clé / valeur) et je pense que c'est plus lisible:

new_dict = {k:v for list_item in list_of_dicts for (k,v) in list_item.items()}

par exemple, remplacez k / v elems comme suit:

new_dict = {str(k).replace(" ","_"):v for list_item in list_of_dicts for (k,v) in list_item.items()}

décompresse le tuple k, v du générateur de dictionnaire .items () après avoir sorti l'objet dict de la liste

Schalton
la source
2
dict1.update( dict2 )

Ceci est asymétrique car vous devez choisir quoi faire avec les clés en double; dans ce cas, dict2écrasera dict1. Échangez-les contre l'autre.

EDIT: Ah, désolé, je n'ai pas vu ça.

Il est possible de le faire en une seule expression:

>>> from itertools import chain
>>> dict( chain( *map( dict.items, theDicts ) ) )
{'a': 1, 'c': 1, 'b': 2, 'd': 2}

Aucun crédit à moi pour ce dernier!

Cependant, je dirais qu'il pourrait être plus pythonique (explicite> implicite, plat> imbriqué) de le faire avec une simple forboucle. YMMV.

Katriel
la source
1
c'est une liste et non un dict: >>> type ([{'a': 1}, {'b': 2}]) <type 'list'>
killown
1

Vous pouvez utiliser se joindre à la fonction de funcy bibliothèque:

from funcy import join
join(list_of_dicts)
Suor
la source
1

Petite amélioration pour la réponse @dietbuddha avec le déballage du dictionnaire de PEP 448 , pour moi, c'est plus lisible de cette façon, aussi, c'est plus rapide aussi :

from functools import reduce
result_dict = reduce(lambda a, b: {**a, **b}, list_of_dicts)

Mais gardez à l'esprit que cela ne fonctionne qu'avec les versions Python 3.5+.

Insomniac631
la source
0
>>> dictlist = [{'a':1},{'b':2},{'c':1},{'d':2, 'e':3}]
>>> dict(kv for d in dictlist for kv in d.iteritems())
{'a': 1, 'c': 1, 'b': 2, 'e': 3, 'd': 2}
>>>

Remarque J'ai ajouté une deuxième paire clé / valeur au dernier dictionnaire pour montrer qu'il fonctionne avec plusieurs entrées. Les clés des dictionnaires plus loin dans la liste écraseront également la même clé d'un dict précédent.

Dave Kirby
la source
-1

dic1 = {'Maria': 12, 'Paco': 22, 'Jose': 23} dic2 = {'Patricia': 25, 'Marcos': 22 'Tomas': 36}

dic2 = dict (dic1.items () + dic2.items ())

et ce sera le résultat:

dic2 {'Jose': 23, 'Marcos': 22, 'Patricia': 25, 'Tomas': 36, 'Paco': 22, 'Maria': 12}

Max Herrera
la source