Nehmen wir an, ich habe eine Liste mit Wörterbüchern:
[
{'id': 1, 'name': 'john', 'age': 34},
{'id': 1, 'name': 'john', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
und ich brauche eine Liste von einzigartigen Wörterbüchern (Entfernen der Duplikate):
[
{'id': 1, 'name': 'john', 'age': 34},
{'id': 2, 'name': 'hanna', 'age': 30},
]
Kann mir jemand auf die effizienteste Weise helfen, dies in Python zu erreichen?
Machen Sie also ein temporäres Diktier mit dem Schlüssel id
. Dadurch werden die Duplikate herausgefiltert . Die values()
des Diktats wird die Liste sein
In 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'}]
In 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'}]
In Python2.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'}]
Die übliche Methode, um nur die allgemeinen Elemente in einer Gruppe zu finden, besteht in der Verwendung der set
-Klasse von Python. Fügen Sie einfach alle Elemente zum Satz hinzu und konvertieren Sie den Satz in eine list
, und die Duplikate sind nicht mehr vorhanden.
Das Problem ist natürlich, dass eine set()
nur Hash-Einträge enthalten kann und eine dict
nicht hashierbar ist.
Wenn ich dieses Problem hätte, wäre meine Lösung, jede dict
in eine Zeichenfolge umzuwandeln, die die dict
darstellt, dann alle Zeichenfolgen zu einer set()
hinzuzufügen, dann die Zeichenfolgenwerte als list()
auszulesen und sie zurück in dict
zu konvertieren.
Eine gute Darstellung einer dict
in Zeichenfolgenform ist das JSON-Format. Und Python hat ein eingebautes Modul für JSON (natürlich json
).
Das verbleibende Problem ist, dass die Elemente in einer dict
nicht geordnet sind. Wenn Python die dict
in eine JSON-Zeichenfolge konvertiert, erhalten Sie möglicherweise zwei JSON-Zeichenfolgen, die gleichwertige Wörterbücher darstellen, jedoch keine identischen Zeichenfolgen sind. Die einfache Lösung besteht darin, das Argument sort_keys=True
zu übergeben, wenn Sie json.dumps()
aufrufen.
BEARBEITEN: Bei dieser Lösung wurde davon ausgegangen, dass eine bestimmte dict
einen anderen Teil haben kann. Wenn wir davon ausgehen können, dass jede dict
mit demselben "id"
-Wert mit jeder anderen dict
mit dem gleichen "id"
-Wert übereinstimmt, ist dies ein Overkill; @ gnibblers Lösung wäre schneller und einfacher.
BEARBEITEN: Nun gibt es einen Kommentar von André Lima, der explizit sagt, dass, wenn es sich bei der ID um ein Duplikat handelt, davon auszugehen ist, dass die gesamte dict
ein Duplikat ist. Diese Antwort ist also übertrieben und ich empfehle die Antwort von @ gnibbler.
Sie können die numpy-Bibliothek verwenden (funktioniert nur für Python2.x):
import numpy as np
list_of_unique_dicts=list(np.unique(np.array(list_of_dicts)))
Wenn die Wörterbücher nur von allen Elementen eindeutig identifiziert werden (ID ist nicht verfügbar), können Sie die Antwort mit JSON verwenden. Das Folgende ist eine Alternative, die JSON nicht verwendet und funktioniert, solange alle Wörterbuchwerte unveränderlich sind
[dict(s) for s in set(frozenset(d.items()) for d in L)]
Hier ist eine einigermaßen kompakte Lösung, obwohl ich vermute, nicht besonders effizient (um es milde auszudrücken):
>>> 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'}]
Da id
zum Erkennen von Duplikaten ausreicht und id
hashable ist, führen Sie sie durch ein Wörterbuch, das id
als Schlüssel hat. Der Wert für jeden Schlüssel ist das ursprüngliche Wörterbuch.
deduped_dicts = dict((item["id"], item) for item in list_of_dicts).values()
In Python 3 gibt values()
keine Liste zurück. Sie müssen die gesamte rechte Seite dieses Ausdrucks in list()
einwickeln, und Sie können das Fleisch des Ausdrucks als Diktierverständnis wirtschaftlicher schreiben:
deduped_dicts = list({item["id"]: item for item in list_of_dicts}.values())
Beachten Sie, dass das Ergebnis wahrscheinlich nicht in derselben Reihenfolge wie das Original liegt. Wenn dies eine Anforderung ist, können Sie einen Collections.OrderedDict
anstelle einer dict
verwenden.
Abgesehen davon kann es durchaus sinnvoll sein, die Daten in einem Wörterbuch, das die Variable id
als Schlüssel verwendet, einfach behalten .
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)
ausgänge:
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]
Erweiterung der John La Rooy-Antwort ( Python - Liste der einzigartigen Wörterbücher ), dadurch etwas flexibler:
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())
Aufrufende Funktion:
sorted_list_of_dicts = dedup_dict_list(
unsorted_list_of_dicts, ['id', 'name'])
Wir können mit 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'}]
_
Beachten Sie etwas anders als die Antwort akzeptieren.
drop_duplicates
überprüft alle Spalten in pandas, wenn alle gleich sind, wird die Zeile gelöscht.
Zum Beispiel :
Wenn wir den 2. dict
Namen von john in peter ändern
_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'}]
_
Verwenden Sie in Python 3.6+ (was ich getestet habe) einfach Folgendes:
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)
Erläuterung: Wir bilden den json.dumps
ab, um die Wörterbücher als json-Objekte zu kodieren, die unveränderlich sind. set
kann dann verwendet werden, um eine Iteration von unique immutables zu erzeugen. Schließlich konvertieren wir mit json.loads
zurück in unsere Wörterbuchdarstellung.
Hier gibt es viele Antworten. Lassen Sie mich noch eine hinzufügen:
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)
Ich weiß nicht, ob Sie nur möchten, dass die ID Ihrer Diktiere in der Liste eindeutig ist, aber wenn es darum geht, einen Satz von Diktaten zu haben, bei denen die Einheit aller Werte der Schlüssel gilt in deinem Verständnis:
>>> 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
Hoffe, es hilft dir oder einer anderen Person, die das Anliegen hat ....
Eine schnelle Lösung besteht darin, eine neue Liste zu erstellen.
sortedlist = []
for item in listwhichneedssorting:
if item not in sortedlist:
sortedlist.append(item)
Ziemlich unkomplizierte Option:
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
Dies ist eine Implementierung mit wenig Speicheraufwand, jedoch mit dem Preis, dass sie nicht so kompakt ist wie der Rest.
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
ausgabe:
[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]