Python - 独特词典列表

时间:2012-06-18 23:30:38

标签: python dictionary

我们说我有一个词典列表:

[
    {'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中实现这一目标吗?

19 个答案:

答案 0 :(得分:190)

所以制作一个临时字典,密钥为id。这会过滤掉重复项。 dict的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'}]

答案 1 :(得分:63)

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

问题当然是set()只能包含可输入的条目,并且dict不可清除。

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

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

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

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

编辑:现在AndréLima明确表示,如果ID是重复的,可以安全地假设整个dict是重复的。所以这个答案是矫枉过正的,我建议@ gnibbler回答。

答案 2 :(得分:17)

您可以使用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)))

答案 3 :(得分:14)

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

,它就会起作用
[dict(s) for s in set(frozenset(d.items()) for d in L)]

答案 4 :(得分:13)

这是一个相当紧凑的解决方案,但我怀疑不是特别有效(温和地说):

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

答案 5 :(得分:7)

由于id足以检测重复项,并且id可以删除:通过以id为键的字典运行它们。每个键的值是原始字典。

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

在Python 3中,values()不返回列表;你需要在list()中包含该表达式的整个右侧,并且你可以更经济地将表达的内容写成字典理解:

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

请注意,结果可能与原始顺序不同。如果这是一项要求,您可以使用Collections.OrderedDict代替dict

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

答案 6 :(得分:6)

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

答案 7 :(得分: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'])

答案 8 :(得分:1)

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

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

list({ item['id'] : item for item in data}.values())

答案 9 :(得分:1)

我们可以使用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将检查熊猫中的所有列,如果全部相同,则将删除该行。

例如:

如果我们将第二个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'}]

答案 10 :(得分: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+有效,因为默认情况下字典是顺序排列的。

答案 11 :(得分:1)

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

sortedlist = []

for item in listwhichneedssorting:
    if item not in sortedlist:
        sortedlist.append(item)

答案 12 :(得分:0)

我不知道您是否只希望列表中的字典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

希望它可以帮助您或其他有问题的人。...

答案 13 :(得分:0)

这里有很多答案,所以让我添加另一个:

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)

答案 14 :(得分:0)

非常简单的选择:

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

答案 15 :(得分:0)

我总结了我的最爱以尝试:

{{3}}

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

答案 16 :(得分:0)

这里提到的所有答案都很好,但是在某些答案中,如果字典项具有嵌套列表或字典,则可能会遇到错误,因此我提出了简单答案

a = [str(i) for i in a]
a = list(set(a))
a = [eval(i) for i in a]

答案 17 :(得分:-1)

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

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

答案 18 :(得分:-3)

这是我找到的解决方案:

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附加到列表中