在Python中删除列表中重复的dict
我有一个dict列表,我想删除具有相同键和值对的dict 对于此列表:在Python中删除列表中重复的dict,python,list,dictionary,Python,List,Dictionary,我有一个dict列表,我想删除具有相同键和值对的dict 对于此列表:[{'a':123},{'b':123},{'a':123}] 我想返回这个:[{'a':123},{'b':123}] 另一个例子: 对于此列表:[{'a':123,'b':1234},{'a':3222,'b':1234},{'a':123,'b':1234}] 我想返回这个:[{'a':123,'b':1234},{'a':3222,'b':1234}]试试这个: [dict(t) for t in {tuple(d.i
[{'a':123},{'b':123},{'a':123}]
我想返回这个:[{'a':123},{'b':123}]
另一个例子:
对于此列表:[{'a':123,'b':1234},{'a':3222,'b':1234},{'a':123,'b':1234}]
我想返回这个:[{'a':123,'b':1234},{'a':3222,'b':1234}]
试试这个:
[dict(t) for t in {tuple(d.items()) for d in l}]
该策略是将字典列表转换为元组列表,其中元组包含字典项。由于元组可以散列,因此可以使用set
(在这里使用set理解,较旧的python替代方法是set(tuple(d.items())表示l中的d)
),然后使用dict从元组中重新创建字典
其中:
l
是原始列表
d
是列表中的词典之一
t
是从字典创建的元组之一
编辑:如果您想保留顺序,上面的一行代码将不起作用,因为set
不会起作用。但是,通过几行代码,您也可以这样做:
l = [{'a': 123, 'b': 1234},
{'a': 3222, 'b': 1234},
{'a': 123, 'b': 1234}]
seen = set()
new_l = []
for d in l:
t = tuple(d.items())
if t not in seen:
seen.add(t)
new_l.append(d)
print new_l
示例输出:
[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
注意:正如@alexis所指出的,两个具有相同键和值的字典可能不会产生相同的元组。如果他们经历不同的添加/删除密钥历史记录,则可能会发生这种情况。如果你的问题是这样的话,那么考虑按他建议的排序<代码> d项()/<代码> 你可以使用一个集合,但是你需要将DICT转换成一个可hash类型。
seq = [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
unique = set()
for d in seq:
t = tuple(d.iteritems())
unique.add(t)
唯一现在等于
set([(('a', 3222), ('b', 1234)), (('a', 123), ('b', 1234))])
要取回dicts:
[dict(x) for x in unique]
有时旧式循环仍然有用。此代码比jcollado的稍长,但非常易于阅读:
a = [{'a': 123}, {'b': 123}, {'a': 123}]
b = []
for i in range(0, len(a)):
if a[i] not in a[i+1:]:
b.append(a[i])
list_of_data = [{'a': 123}, {'b': 123}, {'a': 123}]
list_of_data_uniq = []
for data in list_of_data:
if data not in list_of_data_uniq:
list_of_data_uniq.append(data)
另一个基于列表理解的一行:
>>> d = [{'a': 123}, {'b': 123}, {'a': 123}]
>>> [i for n, i in enumerate(d) if i not in d[n + 1:]]
[{'b': 123}, {'a': 123}]
这里因为我们可以使用dict
比较,所以我们只保留不在初始列表其余部分的元素(这个概念只能通过索引n
访问,因此使用enumerate
)。如果您想保留顺序,那么您可以这样做
from collections import OrderedDict
print OrderedDict((frozenset(item.items()),item) for item in data).values()
# [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
print {frozenset(item.items()):item for item in data}.values()
# [{'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
如果顺序不重要,那么你可以做
from collections import OrderedDict
print OrderedDict((frozenset(item.items()),item) for item in data).values()
# [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
print {frozenset(item.items()):item for item in data}.values()
# [{'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
如果在反序列化JSON对象等嵌套字典上操作,则其他答案将不起作用。在这种情况下,您可以使用:
import json
set_of_jsons = {json.dumps(d, sort_keys=True) for d in X}
X = [json.loads(t) for t in set_of_jsons]
不是通用答案,但如果您的列表碰巧按某个键进行了排序,如下图所示:
l=[{'a': {'b': 31}, 't': 1},
{'a': {'b': 31}, 't': 1},
{'a': {'b': 145}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 112}, 't': 3}]
那么解决方案就简单到:
import itertools
result = [a[0] for a in itertools.groupby(l)]
结果:
[{'a': {'b': 31}, 't': 1},
{'a': {'b': 145}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 112}, 't': 3}]
使用嵌套字典并(显然)保留顺序。如果使用第三方软件包可以,那么您可以使用:
它保留了原始列表的顺序,ut还可以通过使用较慢的算法(其中O(n*m)
处理字典等不易损坏的项目,n
是原始列表中的元素,m
是原始列表中唯一的元素,而不是O(n)
)。如果键和值都是可散列的,您可以使用该函数的key
参数为“唯一性测试”创建可散列项(以便它在O(n)
中工作)
对于字典(它独立于顺序进行比较),您需要将它映射到另一个这样比较的数据结构,例如frozenset
:
>>> list(unique_everseen(l, key=lambda item: frozenset(item.items())))
[{'a': 123}, {'b': 123}]
请注意,不应使用简单的元组方法(不进行排序),因为相等的字典不一定具有相同的顺序(即使在Python 3.7中,插入顺序,而不是绝对顺序,是有保证的):
如果键不可排序,即使对元组排序也可能不起作用:
>>> d3 = {1: 1, 'a': 'a'}
>>> tuple(sorted(d3.items()))
TypeError: '<' not supported between instances of 'str' and 'int'
为完整起见,以下是仅包含重复项的列表的时间安排:
# this is the only change for the benchmark
arguments = {2**i: [{'a': 1} for j in range(2**i)] for i in range(2, 12)}
计时没有明显变化,只有unique\u everseen
没有键
功能,这是最快的解决方案。但是,对于具有不可破坏值的函数来说,这只是最好的情况(因此不具有代表性),因为它的运行时间取决于列表中唯一值的数量:O(n*m)
,在这种情况下,它仅为1,因此在O(n)
中运行
免责声明:我是iteration\u utilities
的作者。如果您在工作流中使用Pandas,一个选项是将字典列表直接提供给pd.DataFrame
构造函数。然后,为获得所需的结果使用适当的方法
import pandas as pd
d = [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
d_unique = pd.DataFrame(d).drop_duplicates().to_dict('records')
print(d_unique)
[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
不是很短,但很容易阅读:
a = [{'a': 123}, {'b': 123}, {'a': 123}]
b = []
for i in range(0, len(a)):
if a[i] not in a[i+1:]:
b.append(a[i])
list_of_data = [{'a': 123}, {'b': 123}, {'a': 123}]
list_of_data_uniq = []
for data in list_of_data:
if data not in list_of_data_uniq:
list_of_data_uniq.append(data)
现在,listlist\u of_data\u uniq
将具有唯一的dict 这里有一个快速的单行解决方案,具有双重嵌套列表理解(基于@Emmanuel的解决方案)
这使用每个dict中的单个键(例如,a
)作为主键,而不是检查整个dict是否匹配
[i for n, i in enumerate(list_of_dicts) if i.get(primary_key) not in [y.get(primary_key) for y in list_of_dicts[n + 1:]]]
这不是OP所要求的,但正是它把我带到了这个线程,所以我想我应该发布我最终得到的解决方案,我知道它可能没有其他答案那么优雅,但是试试这个怎么样:
arts = list of dicts
arts_alt = []
arts_alt = [arts_alt.append(art) for art in arts if art not in arts_alt]
arts_alt是您需要的许多搜索重复值和键的好例子,下面是我们过滤列表中整个字典重复数据的方法。如果源数据由精确格式的字典组成并查找重复项,请使用dupKeys=[]。否则,将dupKeys=设置为不希望有重复项的数据的键名称,可以是1到n个键。它并不优雅,但很有效,而且非常灵活
import binascii
collected_sensor_data = [{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-163","data":"ZYZYZYY"},
{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-97", "data":"QQQQQZZ"}]
dupKeys = ["sensor_id", "data"]
def RemoveDuplicateDictData(collected_sensor_data, dupKeys):
checkCRCs = []
final_sensor_data = []
if dupKeys == []:
for sensor_read in collected_sensor_data:
ck1 = binascii.crc32(str(sensor_read).encode('utf8'))
if not ck1 in checkCRCs:
final_sensor_data.append(sensor_read)
checkCRCs.append(ck1)
else:
for sensor_read in collected_sensor_data:
tmp = ""
for k in dupKeys:
tmp += str(sensor_read[k])
ck1 = binascii.crc32(tmp.encode('utf8'))
if not ck1 in checkCRCs:
final_sensor_data.append(sensor_read)
checkCRCs.append(ck1)
return final_sensor_data
final_sensor_data = [{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-163","data":"ZYZYZYY"},
{"sensor_id":"nw-97", "data":"QQQQQZZ"}]
最简单的方法是,将列表中的每个项转换为字符串,因为字典是不可散列的。然后可以使用set删除重复项
list_org = [{'a': 123}, {'b': 123}, {'a': 123}]
list_org_updated = [ str(item) for item in list_org]
print(list_org_updated)
["{'a': 123}", "{'b': 123}", "{'a': 123}"]
unique_set = set(list_org_updated)
print(unique_set)
{"{'b': 123}", "{'a': 123}"}
您可以使用集合,但如果确实需要列表,请添加以下内容:
import ast
unique_list = [ast.literal_eval(item) for item in unique_set]
print(unique_list)
[{'b': 123}, {'a': 123}]
你能告诉我们更多关于你试图解决的实际问题吗?这似乎是一个奇怪的问题。我正在合并一些目录,其中有重复的。所以我需要去掉这些