2011-08-11 149 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的知識... –