使用Python删除对象列表中的重复项

问题描述 投票:0回答:8

我有一个对象列表,还有一个充满记录的数据库表。我的对象列表有一个标题属性,我想从列表中删除任何具有重复标题的对象(保留原始对象)。

然后我想检查我的对象列表是否有数据库中任何记录的重复项,如果有,请在将这些项目添加到数据库之前从列表中删除这些项目。

我已经看到了从列表中删除重复项的解决方案,如下所示:

myList = list(set(myList))
,但我不确定如何使用对象列表来做到这一点?

我也需要维护对象列表的顺序。我也在想也许我可以使用

difflib
来检查标题中的差异。

python mysql sqlobject
8个回答
72
投票

仅当您知道重复项是什么时,

set(list_of_objects)
才会删除重复项,也就是说,您需要定义对象的唯一性。

为了做到这一点,您需要使对象可散列。您需要定义

__hash__
__eq__
方法,具体方法如下:

http://docs.python.org/glossary.html#term-hashable

不过,您可能只需要定义

__eq__
方法。

编辑:如何实现

__eq__
方法:

正如我提到的,您需要知道对象的唯一性定义。假设我们有一本具有author_name和title属性的书,它们的组合是唯一的(因此,我们可以有很多斯蒂芬·金创作的书,也可以有很多名为《闪灵》的书,但只有一本名为《闪灵》的书是斯蒂芬·金写的),那么执行如下:

def __eq__(self, other):
    return self.author_name==other.author_name\
           and self.title==other.title

类似地,这就是我有时实现

__hash__
方法的方式:

def __hash__(self):
    return hash(('title', self.title,
                 'author_name', self.author_name))

您可以检查,如果您创建具有相同作者和标题的 2 本书的列表,则书籍对象将 相同(使用

is
运算符)并且 相等(使用
==
运算符)。另外,当使用
set()
时,它会删除一本书。

编辑:这是我的一个旧答案,但我现在才注意到它有一个错误,该错误在最后一段中用删除线纠正:与

hash()
。但是,如果您打算将它们用作集合的元素或字典中的键,则使用对象的哈希性。
    
由于它们不可散列,因此您不能直接使用集合。标题应该是。


28
投票

True

您需要描述第二部分使用的数据库/ORM 等。


如果你不能(或不会)为对象定义

is

7
投票

seen_titles = set() new_list = [] for obj in myList: if obj.title not in seen_titles: new_list.append(obj) seen_titles.add(obj.title)

请注意,这将包含给定键的 

last
 实例,例如
对于 
__eq__

,你会得到 unique = list({item.attribute: item for item in mylist}.values()) 。您可以使用

mylist = [Item(attribute=1, tag='first'), Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]
(如果存在完整列表)来解决此问题。
    
这看起来很小:


6
投票

对于不可散列的类型,您可以使用
字典理解

3
投票
默认不支持可哈希类型

mylist[::-1] 请注意,这将仅根据

new_dict = dict() for obj in myList: if obj.title not in new_dict: new_dict[obj.title] = obj
 考虑重复项,并将最后一个匹配的对象作为 
{ row.title : row for row in rows }.values()

。这意味着如果您的行可能具有相同的标题但其他属性的值不同,那么这将不起作用。

例如
row.title

如果您想匹配

row.title
中的多个字段,您可以进一步扩展:

[{"title": "test", "myval": 1}, {"title": "test", "myval": 2}] ==> [{"title": "test", "myval": 2}]

空字符 

row
 用作字段之间的分隔符。这假设 
{ f"{row.title}\0{row.value}" : row for row in rows }.values()

\0
中均未使用空字符。
    
为此需要 

row.title

0
投票
row.value


将对象添加到集合中需要 
__hash__
,因为

python 的集合是作为哈希表实现的

。默认情况下,数字、字符串和元组等不可变对象是可哈希的。


然而,由于鸽巢原理,哈希冲突(两个不同的对象哈希为相同的值)是不可避免的。因此,仅使用哈希值无法区分两个对象,用户必须指定自己的 __eq__ 函数。因此,用户提供的实际哈希函数并不重要,但最好尽量避免哈希冲突以提高性能(请参阅

实现 __hash__() 的正确且良好的方法是什么?

)。

    
我最近最终使用了下面的代码。它与其他答案类似,因为它迭代列表并记录它所看到的内容,然后删除它已经看到的任何项目,但它不会创建重复的列表,而是只是从原始列表中删除该项目。


0
投票

这很简单,朋友们:-

-15
投票

a = [5,6,7,32,32,32,32,32,32,32,32]
a = 列表(集合(a))

打印(一)

__eq__
就是这样! :)

© www.soinside.com 2019 - 2024. All rights reserved.