219

假设我有一个字典列表:

[
    {'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},
]
4

22 回答 22

309

所以做一个临时的字典,关键是id. 这会过滤掉重复项。的values()dict 将是列表

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

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

在 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'}]
于 2012-06-18T23:42:23.153 回答
103

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

当然,问题在于 aset()只能包含可散列的条目,而 adict不可散列。

如果我遇到这个问题,我的解决方案是将每个字符串转换dict为代表 的字符串dict,然后将所有字符串添加到 a中,set()然后将字符串值读出为 alist()并转换回dict.

字符串形式的一个很好的表示dict是 JSON 格式。Python 有一个用于 JSON 的内置模块(json当然称为)。

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

编辑:这个解决方案假设给定dict的任何部分都可以不同。如果我们可以假设dict具有相同"id"值的每个将匹配dict具有相同值的每个其他"id",那么这是矫枉过正的;@gnibbler 的解决方案会更快更容易。

编辑:现在有来自 André Lima 的评论明确指出,如果 ID 是重复的,则可以安全地假设整个 ID 是dict重复的。所以这个答案有点矫枉过正,我推荐@gnibbler 的答案。

于 2012-06-18T23:44:27.623 回答
60

如果字典仅由所有项目唯一标识(ID 不可用),您可以使用 JSON 来使用答案。以下是不使用 JSON 的替代方法,只要所有字典值都是不可变的,它就可以工作

[dict(s) for s in set(frozenset(d.items()) for d in L)]
于 2016-07-22T08:00:14.633 回答
21

这是一个相当紧凑的解决方案,尽管我怀疑不是特别有效(委婉地说):

>>> 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'}]
于 2012-06-18T23:47:40.690 回答
18

您可以使用 numpy 库(仅适用于 Python2.x):

   import numpy as np 

   list_of_unique_dicts=list(np.unique(np.array(list_of_dicts)))

要使其与 Python 3.x(和最新版本的 numpy)一起使用,您需要将 dicts 数组转换为 numpy 字符串数组,例如

list_of_unique_dicts=list(np.unique(np.array(list_of_dicts).astype(str)))
于 2013-11-06T04:25:08.640 回答
10
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)

输出:

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

于 2012-06-18T23:52:59.777 回答
8

由于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())

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

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

于 2012-06-18T23:45:31.063 回答
6

我们可以做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'}]

注意与接受答案略有不同。

drop_duplicates将检查 pandas 中的所有列,如果都相同,则该行将被删除。

例如 :

如果我们将第二个dict名字从john更改为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'}]
于 2019-06-07T01:37:56.670 回答
4

我不知道您是否只希望列表中的 dicts 的 id 是唯一的,但如果目标是拥有一组 dict ,其中唯一性在所有键的值上..您应该使用像这样的元组键在你的理解中:

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

希望它可以帮助您或其他有顾虑的人....

于 2018-06-26T17:11:40.980 回答
3

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

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)
于 2019-12-13T14:33:20.953 回答
3

这里有很多答案,所以让我再补充一个:

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)
于 2019-03-13T13:24:10.733 回答
3

扩展 John La Rooy ( Python - List of unique dictionaries ) 答案,使其更加灵活:

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())

调用函数:

sorted_list_of_dicts = dedup_dict_list(
    unsorted_list_of_dicts, ['id', 'name'])
于 2017-09-04T16:14:16.393 回答
3

在 python 3 中,简单的技巧,但基于唯一字段(id):

data = [ {'id': 1}, {'id': 1}]

list({ item['id'] : item for item in data}.values())
于 2021-04-02T08:30:30.923 回答
1

在 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.dumps以将字典编码为 json 对象,这些对象是不可变的。set然后可用于生成唯一不可变的可迭代。最后,我们使用json.loads. 请注意,最初,必须按键排序才能以独特的形式排列字典。这对 Python 3.6+ 有效,因为字典是默认排序的。

于 2018-10-02T19:47:00.157 回答
1

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

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]
于 2021-09-25T00:26:39.530 回答
1

好吧,这里提到的所有答案都很好,但是在某些答案中,如果字典项目有嵌套列表或字典,可能会遇到错误,所以我建议简单的答案

a = [str(i) for i in a]
a = list(set(a))
a = [eval(i) for i in a]
于 2020-05-27T21:20:57.970 回答
0

如果字典中没有唯一id的,那么我会保持简单并定义如下函数:

def unique(sequence):
    result = []
    for item in sequence:
        if item not in result:
            result.append(item)
    return result

这种方法的优点是您可以将此函数重用于任何可比较的对象。它使您的代码非常易读,适用于所有现代版本的 Python,保留字典中的顺序,并且与其替代品相比也很快。

>>> L = [
... {'id': 1, 'name': 'john', 'age': 34},
... {'id': 1, 'name': 'john', 'age': 34},
... {'id': 2, 'name': 'hanna', 'age': 30},
... ] 
>>> unique(L)
[{'id': 1, 'name': 'john', 'age': 34}, {'id': 2, 'name': 'hanna', 'age': 30}]
于 2022-02-18T12:11:11.753 回答
0

一个快速而肮脏的解决方案就是生成一个新列表。

sortedlist = []

for item in listwhichneedssorting:
    if item not in sortedlist:
        sortedlist.append(item)
于 2016-09-17T23:58:20.400 回答
0

让我添加我的。

  1. 排序目标字典,以便 {'a' : 1, 'b': 2} 和​​ {'b': 2, 'a': 1} 不会被区别对待

  2. 把它做成json

  3. 通过 set 去重(因为 set 不适用于 dicts)

  4. 再次,通过 json.loads 把它变成 dict

import json

[json.loads(i) for i in set([json.dumps(i) for i in [dict(sorted(i.items())) for i in target_dict]])]
于 2021-09-27T08:08:21.353 回答
-1

非常简单的选项:

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
于 2012-06-18T23:48:36.807 回答
-2

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

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'}]
于 2012-06-18T23:52:35.937 回答
-4

这是我找到的解决方案:

usedID = []

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

for each in x:
    if each['id'] in usedID:
        x.remove(each)
    else:
        usedID.append(each['id'])

print x

基本上,您检查列表中是否存在 ID,如果存在,则删除字典,如果不存在,则将 ID 附加到列表中

于 2012-06-18T23:43:02.130 回答