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

r1zhe5dt  于 2022-12-17  发布在  Mysql
关注(0)|答案(9)|浏览(195)

我有一个对象列表和一个满是记录的数据库表,对象列表有一个title属性,我想从列表中删除所有标题重复的对象(保留原来的标题)。
然后我想检查我的对象列表是否有数据库中任何记录的任何重复项,如果有,在将它们添加到数据库之前从列表中删除这些项。
我见过从列表中删除重复项的解决方案,如下所示:myList = list(set(myList)),但我不知道如何对对象列表执行此操作?
我也需要维护我的对象列表的顺序。我还在想也许我可以使用difflib来检查标题中的差异。

eimct9ow

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),那么实现如下:

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()时,它将删除一本书。

编辑:这是我的一个旧答案,但我现在才注意到它有一个错误,在最后一段用删除线纠正了这个错误:具有相同hash()的对象在与is比较时不会给予True。但是,如果您打算将它们用作set的元素或字典中的键,则使用对象的散列性。

ubof19bj

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等。

j8ag8udp

j8ag8udp3#

这看起来非常小:

new_dict = dict()
for obj in myList:
    if obj.title not in new_dict:
        new_dict[obj.title] = obj
zqry0prt

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](如果存在完整列表)来绕过这个问题。

qqrboqgw

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中的多个字段,可以进一步扩展:

{ f"{row.title}\0{row.value}" : row for row in rows }.values()

空字符\0用作字段之间的分隔符。这里假设空字符在row.titlerow.value中均未使用。

1qczuiv0

1qczuiv06#

__hash____eq__都是必需的。
python's sets are implemented as hashtables开始,需要__hash__才能将对象添加到集合中。默认情况下,数字、字符串和元组等不可变对象是可哈希的。
然而,由于鸽子洞原理,散列冲突(两个不同的对象散列到相同的值)是不可避免的。因此,两个对象不能仅仅使用它们的散列来区分,用户必须指定它们自己的__eq__函数。因此,用户提供的实际散列函数并不重要,尽管为了性能最好尽量避免散列冲突(参见What's a correct and good way to implement hash()?)。

tvmytwxo

tvmytwxo7#

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

seen = {}
for obj in objList:
    if obj["key-property"] in seen.keys():
        objList.remove(obj)
    else:
        seen[obj["key-property"]] = 1
fwzugrvs

fwzugrvs8#

如果您想保留原始顺序,请使用它:

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

如果你不在乎订购,那么使用它:

new_list = list(set(my_list))
hwazgwia

hwazgwia9#

它很容易的朋友:-
a = [5、6、7、32、32、32、32、32、32、32]
a =列表(组(a))
打印(a)

[5,6,7,32]

就是这样!:)

相关问题