2014-01-14 36 views
1

是它更有效的檢查,如果一個項目已經在列表中添加它之前:列表成員測試或設置

for word in open('book.txt','r').read().split(): 
if word in list: 
    pass 
else: 
    list.append(item) 

或在其上添加的一切,然後運行set()?像這樣:

for word in open('book.txt','r').read().split(): 
    list.append(word) 
list = set(list) 
+2

你想只有獨特的元素?如果否,請在此停止,否則,訂單是否重要? – thefourtheye

+2

''set'應該像這樣構造:'listobject = set(listobject)' – thefourtheye

+2

不要使用'list'作爲變量名,它會影響內建列表函數 – thefourtheye

回答

6

如果最終目的是構建一套,直接構造它,不與理會名單:

words = set(open('book.txt','r').read().split()) 

這將是簡單高效。

就像你原來的代碼一樣,這有不利於首先將整個文件讀入內存。如果這是一個問題,這可以通過讀取一行在一個時間來解決:(感謝@Steve傑索普的建議)

words = set(word for line in open('book.txt', 'r') for word in line.split()) 

絕對不採取第一種方式在你的問題,除非你知道這個列表很簡短,因爲它需要掃描每一個單詞的整個列表。

+0

我正在構造一個獨特單詞集的列表,據我所知不能存儲單詞,'issuperset'只會告訴我,如果該集包含構建該單詞所需的字母 –

+2

@ChuckFulminata,設置_can_存儲字符串。如果你傳遞一個字符串作爲參數設置,它當然會把它當作一系列字符。嘗試'set(['foo','bar','baz'])' –

+2

我不會用'set.union',這會產生一大堆越來越大的集合並丟棄它們:'words = set (在line.split())中打開的單詞('book.txt','r')。 –

1

這是值得測試找出;但我經常使用理解來過濾我的列表,並且我發現這很有效;特別是如果代碼是實驗性的並且可能會發生變化。

l = list(open('book.txt', 'r').read().split()) 
unique_l = list(set(l)) 
# maybe something else: 
good_l = [ word for word in l if not word in naughty_words ] 

我聽說這有助於提高效率;但正如我所說,一個測試告訴更多。

+0

爲什麼喜歡列表理解生成器或集合理解? –

+0

您可以像這樣使用set comprehension({open for('book.txt','r')。read()。split()}'。根本沒有必要創建一個列表:) – thefourtheye

+0

是的,在我的答案衝,我編輯。 @Steve,我對發電機沒有任何反應。我仍然需要維護許多版本的Python的兼容性,所以我不使用字典解析;通常使用dict()圍繞生成器或列表理解。 –

1

A set是一個散列表,而list是一個數組。 set成員資格測試是O(1),而列表成員資格測試是O(n)。如果有的話,您應該使用set過濾list,而不是使用list過濾set

+0

除非我誤解了你的意思,否則我正在過濾一個列表 –

+1

@ChuckFulminata不,你正在做相反的事情。在構建'list'時,你正在做所有的過濾,然後你使用它來創建一個set =>你正在使用'list'過濾一個'set'。 – Bakuriu

+0

您正在使用列表中的成員資格測試來過濾數據,然後將其轉換爲集合。如果你想最終得到一個集合,你根本不需要一個列表,但是如果你的意思是要有一個列表(例如,因爲順序很重要)的獨特,那麼在一個集合上進行成員過濾將會更有效率在許多情況下。當然,它仍然是YMMV,因爲根據重複頻率和輸入長度的不同,插入兩者可能會超過任何成員資格測試成本。 –

1

該算法與word in list是一個昂貴的操作。爲什麼?因爲要查看某個項目是否在列表中,您必須檢查列表中的每個項目。每次。這是一個Shlemiel the painter algorithm。每個查找都是O(n),並且您會執行n次。沒有啓動成本,但它很快就會變得非常昂貴。最後,您不止一次查看每個項目 - 平均而言,len(列表)/ 2次。

看看事情是否在集合中,是(通常)更便宜。項目被散列,所以你計算散列,看那裏,如果它不在那裏,它不在集合 - O(1)。您必須首次創建該設置,因此您只需查看每個項目一次。然後你再看看每件物品,看看它是否已經在你的設置中。仍然是整體O(n)。

因此,做list(set(mylist))絕對比您的第一個解決方案更可取。

+1

它不是指數。 –

+0

對不起,你對!列表中的詞是O(n),這使得第一個算法是指數型的。 –

+3

第一種算法也不是指數函數,它是'O(n^2)'。 –

0

@ NPE的回答沒有明確地關閉文件。最好使用上下文管理器

with open('book.txt','r') as fin: 
    words = set(fin.read().split()) 

對於正常的文本文件,這可能就足夠了。例如,如果它是一個完整的DNA序列,那麼您可能不希望一次將整個文件讀入內存。

+0

''r''是默認模式:)並且等待,您正在對'set'對象調用'read' ? – thefourtheye

+0

'SyntaxError:invalid syntax' – Bakuriu

+0

對不起,分散了一會兒。 @thefourtheye,有些人更喜歡明確模式,特別是自Python3以來 –