Disons que j'ai une liste de dictionnaires:
[
{'id': 1, 'name': 'john', 'age': 34},
{'id': 1, 'name': 'john', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
et je dois obtenir une liste de dictionnaires uniques (en supprimant les doublons):
[
{'id': 1, 'name': 'john', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
Quelqu'un peut-il m'aider avec le moyen le plus efficace d'y parvenir en Python?
Faites donc un dict temporaire avec la clé id
. Ceci filtre les doublons . La values()
du dict sera la liste
En Python2.7
>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ]
>>> {v['id']:v for v in L}.values()
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]
En Python3
>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ]
>>> list({v['id']:v for v in L}.values())
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]
En Python 2.5/2.6
>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ]
>>> dict((v['id'],v) for v in L).values()
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]
Le moyen habituel de rechercher uniquement les éléments communs d'un ensemble consiste à utiliser la classe set
de Python. Il suffit d’ajouter tous les éléments à l’ensemble, puis de le convertir en list
et de supprimer les doublons.
Le problème, bien sûr, est qu'un set()
ne peut contenir que des entrées pouvant être remplies et qu'un dict
ne l'est pas.
Si j'avais ce problème, ma solution serait de convertir chaque dict
en une chaîne qui représente le dict
, puis d'ajouter toutes les chaînes à un set()
, puis de lire les valeurs de chaîne en tant que list()
et de les reconvertir en dict
.
Le format JSON est une bonne représentation de dict
sous forme de chaîne. Et Python a un module intégré pour JSON (appelé json
bien sûr).
Le problème restant est que les éléments d'une dict
ne sont pas ordonnés et lorsque Python convertit la dict
en une chaîne JSON, vous pouvez obtenir deux chaînes JSON qui représentent des dictionnaires équivalents mais ne sont pas des chaînes identiques. La solution simple consiste à passer l'argument sort_keys=True
lorsque vous appelez json.dumps()
.
EDIT: Cette solution supposait qu’une donnée dict
pouvait avoir une partie différente. Si nous pouvons supposer que chaque dict
avec la même valeur "id"
correspond à chaque dict
avec la même valeur "id"
, il s'agit d'un overkill; La solution de @ gnibbler serait plus rapide et plus simple.
EDIT: Il y a maintenant un commentaire d'André Lima qui dit explicitement que si l'ID est un doublon, il est prudent de supposer que la totalité de la dict
est un duplicata. Donc, cette réponse est exagérée et je recommande la réponse de @ gnibbler.
Vous pouvez utiliser la bibliothèque numpy (ne fonctionne que pour Python2.x):
import numpy as np
list_of_unique_dicts=list(np.unique(np.array(list_of_dicts)))
Si les dictionnaires ne sont identifiés que de manière unique par tous les éléments (l'ID n'est pas disponible), vous pouvez utiliser la réponse à l'aide de JSON. Voici une alternative qui n'utilise pas JSON et fonctionne tant que toutes les valeurs du dictionnaire sont immuables.
[dict(s) for s in set(frozenset(d.items()) for d in L)]
Voici une solution assez compacte, même si je soupçonne qu’elle n’est pas particulièrement efficace (pour le dire gentiment):
>>> ds = [{'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30}
... ]
>>> map(dict, set(Tuple(sorted(d.items())) for d in ds))
[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]
Puisque id
est suffisant pour détecter les doublons, et que id
est hashable: exécutez-les dans un dictionnaire dont la clé est id
. La valeur pour chaque clé est le dictionnaire d'origine.
deduped_dicts = dict((item["id"], item) for item in list_of_dicts).values()
En Python 3, values()
ne renvoie pas de liste; vous devrez envelopper tout le côté droit de cette expression dans list()
, et vous pouvez écrire la viande de l'expression de manière plus économique en tant que compréhension dictée:
deduped_dicts = list({item["id"]: item for item in list_of_dicts}.values())
Notez que le résultat ne sera probablement pas dans le même ordre que l'original. Si cela est nécessaire, vous pouvez utiliser un Collections.OrderedDict
au lieu d'une dict
.
Soit dit en passant, il peut être judicieux de simplement conserver les données dans un dictionnaire utilisant la clé id
comme clé pour commencer.
a = [
{'id':1,'name':'john', 'age':34},
{'id':1,'name':'john', 'age':34},
{'id':2,'name':'hanna', 'age':30},
]
b = {x['id']:x for x in a}.values()
print(b)
les sorties:
[{'age': 34 ans, 'id': 1, 'nom': 'john'}, {'age': 30 ans, 'id': 2, 'nom': 'hanna'}]
Développement de John La Rooy ( Python - Liste de dictionnaires uniques ), ce qui le rend un peu plus flexible:
def dedup_dict_list(list_of_dicts: list, columns: list) -> list:
return list({''.join(row[column] for column in columns): row
for row in list_of_dicts}.values())
Fonction d'appel:
sorted_list_of_dicts = dedup_dict_list(
unsorted_list_of_dicts, ['id', 'name'])
On peut faire avec pandas
_import pandas as pd
yourdict=pd.DataFrame(L).drop_duplicates().to_dict('r')
Out[293]: [{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]
_
Remarquez légèrement différent de la réponse accepter.
drop_duplicates
vérifiera toutes les colonnes de pandas, si toutes identiques, la ligne sera supprimée.
Par exemple :
Si nous changeons le 2nd dict
nom de john en peter
_L=[
{'id': 1, 'name': 'john', 'age': 34},
{'id': 1, 'name': 'peter', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
pd.DataFrame(L).drop_duplicates().to_dict('r')
Out[295]:
[{'age': 34, 'id': 1, 'name': 'john'},
{'age': 34, 'id': 1, 'name': 'peter'},# here will still keeping the dict in the out put
{'age': 30, 'id': 2, 'name': 'hanna'}]
_
En python 3.6+ (ce que j'ai testé), utilisez simplement:
import json
#Toy example, but will also work for your case
myListOfDictionaries = [{'a':1,'b':2},{'a':1,'b':2},{'a':1,'b':3}]
myListOfUniqueDictionaries = list(map(json.loads,set(list(map(json.dumps, myListOfDictionaries)))))
print(myListOfUniqueDictionaries)
Explication: nous mappons le json.dumps
pour coder les dictionnaires sous forme d'objets json, qui sont immuables. set
peut alors être utilisé pour produire un itérable de unique immutables. Enfin, nous reconvertissons notre représentation dans le dictionnaire avec json.loads
.
Il y a beaucoup de réponses ici, alors laissez-moi en ajouter une autre:
import json
from typing import List
def dedup_dicts(items: List[dict]):
dedupped = [ json.loads(i) for i in set(json.dumps(item, sort_keys=True) for item in items)]
return dedupped
items = [
{'id': 1, 'name': 'john', 'age': 34},
{'id': 1, 'name': 'john', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
dedup_dicts(items)
Je ne sais pas si vous voulez seulement que l'identifiant de vos cartes dans la liste soit unique, mais si l'objectif est d'avoir un ensemble de dict où l'unicité est sur toutes les valeurs des clés .. vous devriez utiliser des clés telles que celle-ci dans votre compréhension:
>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... {'id':2,'name':'hanna', 'age':50}
... ]
>>> len(L)
4
>>> L=list({(v['id'], v['age'], v['name']):v for v in L}.values())
>>>L
[{'id': 1, 'name': 'john', 'age': 34}, {'id': 2, 'name': 'hanna', 'age': 30}, {'id': 2, 'name': 'hanna', 'age': 50}]
>>>len(L)
3
J'espère que cela vous aidera, vous ou une autre personne ayant le problème ...
Une solution simple et rapide consiste simplement à générer une nouvelle liste.
sortedlist = []
for item in listwhichneedssorting:
if item not in sortedlist:
sortedlist.append(item)
Option assez simple:
L = [
{'id':1,'name':'john', 'age':34},
{'id':1,'name':'john', 'age':34},
{'id':2,'name':'hanna', 'age':30},
]
D = dict()
for l in L: D[l['id']] = l
output = list(D.values())
print output
Voici une implémentation avec peu de surcharge de mémoire au prix de ne pas être aussi compact que le reste.
values = [ {'id':2,'name':'hanna', 'age':30},
{'id':1,'name':'john', 'age':34},
{'id':1,'name':'john', 'age':34},
{'id':2,'name':'hanna', 'age':30},
{'id':1,'name':'john', 'age':34},]
count = {}
index = 0
while index < len(values):
if values[index]['id'] in count:
del values[index]
else:
count[values[index]['id']] = 1
index += 1
sortie:
[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]