Python – 独特词典的列表
比方说,我有一个字典列表:
[ {'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}, ]
任何人都可以帮助我以最有效的方式来实现这个在Python?
因此,使用id
作为临时字典。 这将筛选出重复项。 字典的values()
将成为列表
在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'}]
寻找集合中常见元素的常用方法是使用Python的set
类。 只需将所有元素添加到该集合,然后将该集合转换为list
,并且重复的bam消失了。
当然,问题是一个set()
只能包含可sorting的条目,而一个dict
是不可散列的。
如果我遇到了这个问题,我的解决scheme是将每个dict
转换为一个代表dict
的string,然后将所有string添加到一个set()
然后将string值读出为list()
并将其转换为dict
。
stringforms的dict
一个很好的代表是JSON格式。 而Python有一个JSON的内置模块(当然称为json
)。
剩下的问题是, dict
中的元素没有sorting,当Python将dict
转换为JSONstring时,可能会得到两个JSONstring表示等效字典,但不是相同的string。 简单的解决方法是在调用json.dumps()
时传递参数sort_keys=True
。
编辑:这个解决scheme假设一个给定的dict
可以有任何不同的部分。 如果我们可以认为每个具有相同"id"
值的dict
都会匹配具有相同"id"
值的其他dict
,那么这是过度的; @ gnibbler的解决scheme会更快,更容易。
编辑:现在有来自AndréLima的意见,明确表示如果ID是重复的,可以安全地假定整个dict
是重复的。 所以这个答案是矫枉过正,我推荐@ gnibbler的答案。
您可以使用numpy库(仅适用于Python2.x):
import numpy as np list_of_unique_dicts=list(np.unique(np.array(list_of_dicts)))
这是一个相当紧凑的解决scheme,虽然我怀疑不是特别有效(说得温和):
>>> 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'}]
由于id
足够用于检测重复,并且id
是可散列的:通过以id
为关键字的字典运行em。 每个键的值是原始字典。
deduped_dicts = dict((item["id"], item) for item in list_of_dicts).values()
在Python 3中, values()
不返回一个列表; 你需要将整个expression式的右边部分包含在list()
,并且可以更经济地编写expression式的内容作为dict理解:
deduped_dicts = list({item["id"]: item for item in list_of_dicts}.values())
请注意,结果可能不会与原来的顺序相同。 如果这是一个要求,你可以使用Collections.OrderedDict
而不是一个dict
。
顺便说一下, 将数据保存在使用id
作为关键字的字典中可能会很有意义。
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'}]
如果字典只能由所有项目唯一标识(ID不可用),则可以使用JSON使用答案。 以下是不使用JSON的替代方法,只要所有的字典值都是不变的,就可以工作
[dict(s) for s in set(frozenset(d.items()) for d in L)]
非常简单的选项:
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
下面是一个很less的内存开销的实现,代价是不像其他的那样紧凑。
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'}]
这是我find的解决scheme:
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附加到列表中
一个快速而肮脏的解决scheme就是生成一个新的列表。
sortedlist = [] for item in listwhichneedssorting: if item not in sortedlist: sortedlist.append(item)
在John La Rooy( Python – 独特词典列表 )上进行扩展,使其更加灵活:
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'])