更新:::帖子中包含了與frozensets相比劣勢集的錯誤指控。我堅持認爲在這個實例中使用一個冷凝集合仍然是明智的,即使不需要散列集合本身,僅僅因爲它在語義上更正確。雖然在實踐中,我可能不會打擾多餘的6個字符。我沒有動力去瀏覽和編輯這篇文章,所以只是建議「指控」鏈接到一些不正確運行的測試。評論中散佈了血淋淋的細節。 :::更新
由布蘭登·克雷格羅德的代碼posted第二塊是相當不錯,但他並沒有對我的建議作出迴應有關使用frozenset(當然,不是當我開始寫這個,反正) ,我會繼續並自己發佈。
手頭承諾的全部基礎是檢查一系列值(L1
)中的每一個值是否都在另一組值中;該組值是L2
和L3
的內容。在這個句子中使用「set」這個詞是說:即使L2
和L3
是list
s,我們並不關心他們的列表類屬性,比如它們的值的順序或者它們的值有多少包含。我們只關心集合(這裏又是)它們共同包含的值。
如果該組值被存儲爲列表,則必須逐個檢查列表元素,檢查每個列表元素。這是相對耗時的,而且是不好的語義:再次,它是一組「值」,而不是一個列表。所以Python有這些整齊的集合類型,它們擁有一堆獨特的值,並且可以快速告訴你是否有某個值。這與python的dict
類型在查找關鍵字時的工作方式基本相同。
套和frozensets是集是可變的,這意味着它們可以在創建之後可以修改之間的差異。這兩種類型的文檔是here。
由於我們需要創建的集合,存儲在L2
和L3
中的值的聯合一旦創建就不會被修改,它在語義上適合使用不可變數據類型。這也有一些性能優勢。那麼,這是有道理的,它會有一些優勢;否則,爲什麼Python將frozenset
作爲內建函數?
更新 ...
布蘭登已經回答了這個問題:冰凍套真正的優勢在於他們的不變性,使他們有可能是hashable,使他們能夠字典鍵或其他組成員。
我跑比較用於創建和查找在相對大的(3000元素)冷凍並可變設定速度一些非正式定時測試;沒有太大的區別。這與上面的鏈接衝突,但支持布蘭登說他們是相同的,但在可變性方面。
... 更新
現在,因爲frozensets是不可改變的,他們沒有更新方法。布蘭登使用set.update
方法來避免創建並丟棄臨時列表以創建集合;我將採取不同的方法。
items = (item for lst in (L2, L3) for item in lst)
這generator expression使得items
一個迭代結束,連續的L2
和L3
內容。不僅如此,它還可以在不創建完整列表的情況下完成 - 完整的中間對象。在生成器中使用嵌套for
表達式有點令人困惑,但我設法通過記住它們的嵌套順序與它們在編寫實際for循環時的順序相同,例如
def get_items(lists):
for lst in lists:
for item in lst:
yield item
即generator function等同於我們分配給items
發電機表達。那麼,除了它是一個參數化的函數定義,而不是直接賦值給一個變量。
無論如何,夠離題了。與發電機有關的大事是他們實際上沒有做任何事情。那麼,至少不是馬上:他們只是將工作設置在稍後完成,當時生成器表達式爲迭代爲。這正式被稱爲懶惰。我們將通過將items
傳遞給frozenset
函數來做到這一點(無論如何,我是這樣做的),該函數遍歷它並返回一個冷凍冷凍集。
unwanted = frozenset(items)
其實你可以結合起來,最後兩行,通過把發電機表達權的通話裏面frozenset
:
unwanted = frozenset(item for lst in (L2, L3) for item in lst)
只要這個整齊的語法技巧的工作由生成器表達式創建的iterator是您要調用的函數的唯一參數。否則,你必須把它寫在它通常單獨的一組括號中,就像你將一個元組作爲參數傳遞給函數一樣。現在
我們可以建立以同樣的方式,布蘭登做了一個新的列表,用list comprehension。這些使用相同的語法生成表達式,基本上做同樣的事情,但他們都渴望,而不是懶(再次,這些都是實際的技術術語),所以他們馬上在項目工作迭代和創建他們的名單。
L4 = [item for item in L1 if item not in unwanted]
這等效於通過一個發電機表達式list
,例如
L4 = list(item for item in L1 if item not in unwanted)
但更習慣。
因此,這將創建列表L4
,含有沒有在任何L2
或L3
的L1
的元素,保持他們在最初的順序和他們的,有數量。
如果你只是想知道這值在L1
但不是在L2
或L3
,它更容易:你剛纔創建集:
L1_unique_values = set(L1) - unwanted
你可以列個清單出來它,as does st0le,但這可能不是你想要的。如果你真的想要的設定值那些只在L1
發現,你可能有一個很好的理由保持這種設置爲set
,或者確實是一個frozenset
:
L1_unique_values = frozenset(L1) - unwanted
... Annnnd,現在完全不同的東西:
from itertools import ifilterfalse, chain
L4 = list(ifilterfalse(frozenset(chain(L2, L3)).__contains__, L1))
沒有一個正確的方法來做這件事,直到你決定你是否照顧或不關心重複和訂購。可能是某種列表理解或根據你所關心的設定工作。 – istruble 2010-10-16 05:40:20
另外,可以假設列表中的所有項目都會一直可用?如果不是,或者有時不會,那將非常重要。 – martineau 2010-10-16 12:03:01
你爲什麼不用套頭?那麼你的「算術」就可以工作。 – poke 2010-10-16 15:41:14