假设我有一个字典列表:

[
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]

如何获得唯一字典的列表(删除重复项)?

[
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]

当前回答

我总结了我最喜欢的尝试:

https://repl.it/@SmaMa/Python-List-of-unique-dictionaries

# ----------------------------------------------
# Setup
# ----------------------------------------------

myList = [
  {"id":"1", "lala": "value_1"},
  {"id": "2", "lala": "value_2"}, 
  {"id": "2", "lala": "value_2"}, 
  {"id": "3", "lala": "value_3"}
]
print("myList:", myList)

# -----------------------------------------------
# Option 1 if objects has an unique identifier
# -----------------------------------------------

myUniqueList = list({myObject['id']:myObject for myObject in myList}.values())
print("myUniqueList:", myUniqueList)

# -----------------------------------------------
# Option 2 if uniquely identified by whole object
# -----------------------------------------------

myUniqueSet = [dict(s) for s in set(frozenset(myObject.items()) for myObject in myList)]
print("myUniqueSet:", myUniqueSet)

# -----------------------------------------------
# Option 3 for hashable objects (not dicts)
# -----------------------------------------------

myHashableObjects = list(set(["1", "2", "2", "3"]))
print("myHashAbleList:", myHashableObjects)

其他回答

由于id足以检测重复项,且id是可哈希的:在以id为键的字典中运行它们。每个键的值都是原始字典。

deduped_dicts = dict((item["id"], item) for item in list_of_dicts).values()

在Python 3中,values()不返回列表;你需要在list()中包装整个表达式的右边,并且你可以将表达式的部分更经济地写成dict理解:

deduped_dicts = list({item["id"]: item for item in list_of_dicts}.values())

注意,结果可能与原始结果的顺序不同。如果这是一个要求,您可以使用集合。OrderedDict而不是dict。

顺便说一句,将数据保存在使用id作为键的字典中可能很有意义。

对象可以放入集合中。您可以使用对象而不是字典,如果需要,在所有set插入后转换回字典列表。例子

class Person:
    def __init__(self, id, age, name):
        self.id = id
        self.age = age
        self.name = name

my_set = {Person(id=2, age=3, name='Jhon')}

my_set.add(Person(id=3, age=34, name='Guy'))

my_set.add({Person(id=2, age=3, name='Jhon')})

# if needed convert to list of dicts
list_of_dict = [{'id': obj.id,
                 'name': obj.name,
                 'age': obj.age} for obj in my_set]

在集合中查找公共元素的通常方法是使用Python的set类。只需将所有元素添加到集合中,然后将集合转换为列表,然后重复的元素就消失了。

当然,问题在于set()只能包含可哈希的条目,而dict是不可哈希的。

如果我遇到这个问题,我的解决方案是将每个dict转换为表示该dict的字符串,然后将所有字符串添加到set()中,然后将字符串值作为列表()读取并转换回dict。

字符串形式的字典的一个很好的表示是JSON格式。Python有一个内置的JSON模块(当然叫做JSON)。

剩下的问题是字典中的元素没有顺序,当Python将字典转换为JSON字符串时,您可能会得到两个表示等效字典的JSON字符串,但它们不是相同的字符串。简单的解决方案是在调用json.dumps()时传递参数sort_keys=True。

编辑:这个解决方案是假设一个给定的字典可以有任何不同的部分。如果我们可以假设每个具有相同“id”值的dict将匹配其他具有相同“id”值的dict,那么这是过度的;@gnibbler的解决方案更快更简单。

编辑:现在有一个来自André Lima的评论明确表示,如果ID是一个副本,那么可以安全地假设整个字典是一个副本。所以这个答案太夸张了,我推荐@gnibbler的答案。

在python 3.6+(我已经测试过了)中,只需使用:

import json

#Toy example, but will also work for your case 
myListOfDicts = [{'a':1,'b':2},{'a':1,'b':2},{'a':1,'b':3}]
#Start by sorting each dictionary by keys
myListOfDictsSorted = [sorted(d.items()) for d in myListOfDicts]

#Using json methods with set() to get unique dict
myListOfUniqueDicts = list(map(json.loads,set(map(json.dumps, myListOfDictsSorted))))

print(myListOfUniqueDicts)

解释:我们正在映射json。转储将字典编码为json对象,这是不可变的。Set可用于生成包含唯一不可变对象的迭代对象。最后,我们使用json.loads转换回字典表示。注意,一开始,必须按键排序才能以唯一的形式排列字典。这对于Python 3.6+是有效的,因为字典在默认情况下是有序的。

这里有一个内存开销很小的实现,代价是不像其他实现那样紧凑。

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

输出:

[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]