Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中删除列表中重复的dict_Python_List_Dictionary - Fatal编程技术网

在Python中删除列表中重复的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

我有一个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.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)

现在,list
list\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}]

你能告诉我们更多关于你试图解决的实际问题吗?这似乎是一个奇怪的问题。我正在合并一些目录,其中有重复的。所以我需要去掉这些