web-dev-qa-db-de.com

Python - Liste der einzigartigen Wörterbücher

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?

105
Limaaf

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'}]
170
John La Rooy

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.

61
steveha

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)))
18
bubble

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)]
12
Sina

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'}]
12
Greg E.

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 .

7
kindall
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'}]

5
Yusuf X

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'])
2

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'}]
_
1
WeNYoBen

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.

1
VanillaSpinIce

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)
0
monkut

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

0
nixmind

Eine schnelle Lösung besteht darin, eine neue Liste zu erstellen.

sortedlist = []

for item in listwhichneedssorting:
    if item not in sortedlist:
        sortedlist.append(item)
0
lyzazel

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

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'}]
0
Samy Vilar