从多个列表创建唯一对象列表
我定义了一个自定义对象,里面有多个字段。
比如说,我有一个学生对象,它包含了姓名、学号和年龄。为了比较两个学生,判断他们是否是同一个人,我实现了一个 __ eq__
方法,这个方法会检查两个学生的年龄、姓名和学号是否一致。
def __eq__(self, other): return self.name == other.name and self.ID == other.ID and self.age == other.age
需要注意的是,学生只是一个例子,所以学生的学号通常是唯一的这一点不在讨论范围内。
假设我有以下的注册名单,里面有任意数量的学生对象。
[S1, S2, S3] [S2, S3] [S3, S5, S4] [S1, S4, S2, S1]
我想创建一个数据结构,里面包含以下元素。
S1, S2, S3, S4, S5
最简单的方法就是初始化一个可以装很多东西的数据结构,取出一个项目,检查它是否已经存在于这个结构中,如果不存在就添加进去。
new_list = some_new_list for each list of students: for each student in the list: check if the student is in new_list #decide what to do
如果我决定用一个简单的列表来实现,随着我的列表不断增长,我可能会进行很多比较,尤其是当我有大量学生和注册名单的时候。
有没有什么高效的方法来实现这个?既可以比较两个对象,又可以利用这个比较方法生成一个唯一的对象集合。
编辑:所以我尝试了一个简单的集合实现。
>>>a = Student("sample", 1234, 18) >>>b = Student("sample", 1234, 18) >>>students = set() >>>students.add(a) >>>b in students False >>>b == a True
我是不是做错了什么?
3 个回答
-3
0
set
这个东西不保证会保持顺序。如果你需要一个能保持顺序的列表:
import itertools
from typing import List
def unique_items(*lists: List) -> List:
"""Return an order-preserving list of unique items from the given lists.
The implemented approach requires that the input items are hashable.
Example: unique_items([1,9,4], [2,4,6,8,8], [3,1]) -> [1, 9, 4, 2, 6, 8, 3]
Ref: https://stackoverflow.com/a/68626841/
"""
return list(dict.fromkeys(itertools.chain(*lists)))
8
from itertools import chain
myset = set(chain(iterable1, iterable2, iterable3, iterable4))
你会得到一些独特的项目,而且每个可迭代对象只会被遍历一次。chain
可以把一系列可迭代对象连接成一个长的可迭代对象。如果你需要排序,可以用sorted(myset)
来得到一个排序后的列表。
你的Student
类需要实现一个__hash__
方法,这个方法要和它的__eq__
方法兼容:
def __hash__(self):
return (self.name, self.ID, self.age).__hash__()