39

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

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

我已经看到了从这样的列表中删除重复项的解决方案:myList = list(set(myList)),但我不确定如何使用对象列表来做到这一点?

我也需要维护我的对象列表的顺序。我也在想也许我可以用它difflib来检查标题的差异。

4

8 回答 8

62

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

为此,您需要使对象可散列。您需要同时定义__hash____eq__方法,方法如下:

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

不过,您可能只需要定义__eq__方法。

编辑:如何实现该__eq__方法:

正如我所提到的,您需要知道对象的唯一性定义。假设我们有一本书,其属性为 author_name 和 title,它们的组合是唯一的,(因此,我们可以有许多 Stephen King 创作的书,以及许多名为 The Shining 的书,但只有一本书名为 The Shining by Stephen King),然后实现如下:

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():这是我的一个旧答案,但我现在才注意到它有错误,在最后一段中用删除线纠正:Trueis. 但是,如果您打算将它们用作集合的元素或用作字典中的键,则使用对象的哈希性。

于 2010-11-13T15:41:37.547 回答
22

由于它们不可散列,因此您不能直接使用集合。标题应该是。

这是第一部分。

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)

不过,您将需要描述您在第二部分中使用的数据库/ORM 等。

于 2010-11-12T21:43:30.413 回答
2

这似乎很小:

new_dict = dict()
for obj in myList:
    if obj.title not in new_dict:
        new_dict[obj.title] = obj
于 2010-11-13T02:32:15.650 回答
0

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

seen = {}
for obj in objList:
    if obj["key-property"] in seen.keys():
        objList.remove(obj)
    else:
        seen[obj["key-property"]] = 1
于 2019-12-17T15:48:35.427 回答
0

如果您不能(或不会)__eq__为对象定义,您可以使用 dict-comprehension 来实现相同的目的:

unique = list({item.attribute:item for item in mylist}.values())

请注意,这将包含给定键的最后一个实例,例如 for mylist = [Item(attribute=1, tag='first'), Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]you get [Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]。您可以通过使用mylist[::-1](如果存在完整列表)来解决此问题。

于 2021-11-24T22:45:15.830 回答
-1

这两者都是必需的__hash____eq__

__hash__需要将对象添加到集合中,因为python 的集合是作为 hashtables 实现的。默认情况下,像数字、字符串和元组这样的不可变对象是可散列的。

但是,由于鸽巢原理,哈希冲突(两个不同的对象哈希到相同的值)是不可避免的。因此,两个对象不能仅使用它们的哈希来区分,用户必须指定它们自己的__eq__函数。因此,用户提供的实际散列函数并不重要,但最好尽量避免散列冲突以提高性能(请参阅什么是实现 __hash__() 的正确和好方法?)。

于 2018-11-26T20:54:42.430 回答
-3

如果要保留原始订单,请使用它:

seen = {}
new_list = [seen.setdefault(x, x) for x in my_list if x not in seen]

如果您不关心订购,请使用它:

new_list = list(set(my_list))
于 2016-11-20T06:55:41.857 回答
-11

它很容易成为朋友:-

a = [5,6,7,32,32,32,32,32,32,32,32]

a = 列表(集合(a))

打印(一)

[5,6,7,32]

就是这样 !:)

于 2011-03-17T12:09:58.163 回答