我有一个对象列表和一个满是记录的数据库表,对象列表有一个title属性,我想从列表中删除所有标题重复的对象(保留原来的标题)。然后我想检查我的对象列表是否有数据库中任何记录的任何重复项,如果有,在将它们添加到数据库之前从列表中删除这些项。我见过从列表中删除重复项的解决方案,如下所示:myList = list(set(myList)),但我不知道如何对对象列表执行此操作?我也需要维护我的对象列表的顺序。我还在想也许我可以使用difflib来检查标题中的差异。
myList = list(set(myList))
difflib
eimct9ow1#
set(list_of_objects)只会在您知道什么是重复项的情况下删除重复项,也就是说,您需要定义对象的唯一性。为了做到这一点,你需要让对象成为hashable,你需要定义__hash__和__eq__方法,方法如下:http://docs.python.org/glossary.html#term-hashable不过,您可能只需要定义__eq__方法。
set(list_of_objects)
__hash__
__eq__
EDIT:如何实现__eq__方法:
正如我提到的,你需要知道你的对象的唯一性定义。假设我们有一本书,属性author_name和title的组合是唯一的,(因此,我们可以有许多书Stephen King authored,许多书命名为The Shining,但只有一本书命名为Stephen King的The Shining),那么实现如下:
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))
你可以检查一下,如果你创建了一个由两本作者和书名相同的书组成的列表,那么这两本书的对象将是相同的(使用is操作符)和相等的(使用==操作符)。另外,当使用set()时,它将删除一本书。
is
==
set()
编辑:这是我的一个旧答案,但我现在才注意到它有一个错误,在最后一段用删除线纠正了这个错误:具有相同hash()的对象在与is比较时不会给予True。但是,如果您打算将它们用作set的元素或字典中的键,则使用对象的散列性。
hash()
True
ubof19bj2#
因为它们是不可散列的,所以不能直接使用集合,但标题应该是可散列的。这是第一部分。
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等。
j8ag8udp3#
这看起来非常小:
new_dict = dict() for obj in myList: if obj.title not in new_dict: new_dict[obj.title] = obj
zqry0prt4#
如果不能(或不愿意)为对象定义__eq__,可以使用dict-comprehension来达到相同的目的:
unique = list({item.attribute:item for item in mylist}.values())
注意这将包含一个给定键的 last 示例,例如对于mylist = [Item(attribute=1, tag='first'), Item(attribute=1, tag='second'), Item(attribute=2, tag='third')],你得到[Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]。你可以通过使用mylist[::-1](如果存在完整列表)来绕过这个问题。
mylist = [Item(attribute=1, tag='first'), Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]
[Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]
mylist[::-1]
qqrboqgw5#
对于不可散列的类型,你可以使用dictionary comprehension来移除所有对象中基于字段的重复对象。这对于Pydantic特别有用,doesn't support hashable types by default:
{ 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中的多个字段,可以进一步扩展:
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或row.value中均未使用。
\0
row.value
1qczuiv06#
__hash__和__eq__都是必需的。从python's sets are implemented as hashtables开始,需要__hash__才能将对象添加到集合中。默认情况下,数字、字符串和元组等不可变对象是可哈希的。然而,由于鸽子洞原理,散列冲突(两个不同的对象散列到相同的值)是不可避免的。因此,两个对象不能仅仅使用它们的散列来区分,用户必须指定它们自己的__eq__函数。因此,用户提供的实际散列函数并不重要,尽管为了性能最好尽量避免散列冲突(参见What's a correct and good way to implement hash()?)。
tvmytwxo7#
我最近使用了下面的代码,它和其他的答案类似,因为它迭代列表并记录它看到的内容,然后删除它已经看到的任何项目,但它不会创建一个重复的列表,而是从原始列表中删除项目。
seen = {} for obj in objList: if obj["key-property"] in seen.keys(): objList.remove(obj) else: seen[obj["key-property"]] = 1
fwzugrvs8#
如果您想保留原始顺序,请使用它:
seen = {} new_list = [seen.setdefault(x, x) for x in my_list if x not in seen]
如果你不在乎订购,那么使用它:
new_list = list(set(my_list))
hwazgwia9#
它很容易的朋友:-a = [5、6、7、32、32、32、32、32、32、32]a =列表(组(a))打印(a)
[5,6,7,32]
就是这样!:)
9条答案
按热度按时间eimct9ow1#
set(list_of_objects)
只会在您知道什么是重复项的情况下删除重复项,也就是说,您需要定义对象的唯一性。为了做到这一点,你需要让对象成为hashable,你需要定义
__hash__
和__eq__
方法,方法如下:http://docs.python.org/glossary.html#term-hashable
不过,您可能只需要定义
__eq__
方法。EDIT:如何实现
__eq__
方法:正如我提到的,你需要知道你的对象的唯一性定义。假设我们有一本书,属性author_name和title的组合是唯一的,(因此,我们可以有许多书Stephen King authored,许多书命名为The Shining,但只有一本书命名为Stephen King的The Shining),那么实现如下:
类似地,我有时也是这样实现
__hash__
方法的:你可以检查一下,如果你创建了一个由两本作者和书名相同的书组成的列表,那么这两本书的对象将是相同的(使用
is
操作符)和相等的(使用==
操作符)。另外,当使用set()
时,它将删除一本书。编辑:这是我的一个旧答案,但我现在才注意到它有一个错误,在最后一段用删除线纠正了这个错误:具有相同
hash()
的对象在与is
比较时不会给予True
。但是,如果您打算将它们用作set的元素或字典中的键,则使用对象的散列性。ubof19bj2#
因为它们是不可散列的,所以不能直接使用集合,但标题应该是可散列的。
这是第一部分。
你需要描述你在第二部分使用的数据库/ORM等。
j8ag8udp3#
这看起来非常小:
zqry0prt4#
如果不能(或不愿意)为对象定义
__eq__
,可以使用dict-comprehension来达到相同的目的:注意这将包含一个给定键的 last 示例,例如对于
mylist = [Item(attribute=1, tag='first'), Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]
,你得到[Item(attribute=1, tag='second'), Item(attribute=2, tag='third')]
。你可以通过使用mylist[::-1]
(如果存在完整列表)来绕过这个问题。qqrboqgw5#
对于不可散列的类型,你可以使用dictionary comprehension来移除所有对象中基于字段的重复对象。这对于Pydantic特别有用,doesn't support hashable types by default:
请注意,这将仅根据
row.title
来考虑重复项,并将取row.title
的最后一个匹配对象。这意味着,如果您的行可能具有相同的标题,但在其他属性中具有不同的值,则这将不起作用。例如
[{"title": "test", "myval": 1}, {"title": "test", "myval": 2}] ==> [{"title": "test", "myval": 2}]
如果要匹配
row
中的多个字段,可以进一步扩展:空字符
\0
用作字段之间的分隔符。这里假设空字符在row.title
或row.value
中均未使用。1qczuiv06#
__hash__
和__eq__
都是必需的。从python's sets are implemented as hashtables开始,需要
__hash__
才能将对象添加到集合中。默认情况下,数字、字符串和元组等不可变对象是可哈希的。然而,由于鸽子洞原理,散列冲突(两个不同的对象散列到相同的值)是不可避免的。因此,两个对象不能仅仅使用它们的散列来区分,用户必须指定它们自己的
__eq__
函数。因此,用户提供的实际散列函数并不重要,尽管为了性能最好尽量避免散列冲突(参见What's a correct and good way to implement hash()?)。tvmytwxo7#
我最近使用了下面的代码,它和其他的答案类似,因为它迭代列表并记录它看到的内容,然后删除它已经看到的任何项目,但它不会创建一个重复的列表,而是从原始列表中删除项目。
fwzugrvs8#
如果您想保留原始顺序,请使用它:
如果你不在乎订购,那么使用它:
hwazgwia9#
它很容易的朋友:-
a = [5、6、7、32、32、32、32、32、32、32]
a =列表(组(a))
打印(a)
就是这样!:)