2011-08-11 47 views
4

我已经定义了一个具有多个字段的自定义对象。从多个列表创建对象的唯一列表

例如说我有一个Student对象,它由一个名称,ID和年龄组成。为了比较两个学生并确定他们是否是同一个学生,我实施了一个__ 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 

我做错了什么?

+2

为什么不使用内置的集合类型?成员测试可能比您在纯Python中希望的效率更高。 –

+0

@omrib,所以遍历每个学生列表,然后调用newSet.add(student)就像它获得的一样好? – MxyL

+0

@agf,哦,我原以为只是检查一个项目是否存在于该集合中就足够了。即:“测试会员资格” – MxyL

回答

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__() 
+0

如果你有一个可变数量的学生列表(全部包含在名为'student_lists'的列表或元组中),你可以使用'set(chain(* student_lists))'。 –

+0

@omrib使用'set(chain.from_iterable(student_lists))',所以'student_lists'不必解压缩。无论谁写了'itertools.chain'这个想法,都不像'map'和'zip'。 – agf

+0

感谢您的提示!现在刷新我对itertools的知识... –