[英]Best / most pythonic way to get an ordered list of unique items
我有一個或多個(不可變的,可散列的)對象的無序序列,可能有重復項,我想得到所有這些對象的排序序列,沒有重復。
現在我正在使用一個集合來快速收集所有丟棄重復項的元素,將其轉換為列表然后對其進行排序:
result = set()
for s in sequences:
result = result.union(s)
result = list(result)
result.sort()
return result
它有效,但我不會稱之為“漂亮”。 有沒有更好的辦法?
這應該工作:
sorted(set(itertools.chain.from_iterable(sequences)))
我很喜歡你的代碼。 它簡單易懂。
我們可以通過鏈接list()
來縮短它一點點:
result = set()
for s in sequences:
result = result.union(s)
return sorted(result)
我真的不想嘗試將其燒掉,但你可以用reduce()
來做到這一點:
result = reduce(lambda s, x: s.union(x), sequences, set())
return sorted(result)
就個人而言,我認為這比上面的內容更難理解,但沉浸在函數式編程中的人可能更喜歡它。
編輯:@agf在這個reduce()
要比我好多了。 從下面的評論:
return sorted(reduce(set().union, sequences))
我不知道這會起作用。 如果我正確理解它是如何工作的,我們給reduce()
一個callable,它實際上是一個set()
一個實例上的方法函數(為了討論起見,將其稱為x
,但請注意,我並不是說Python會將名稱x
與此對象綁定)。 然后reduce()
將從sequences
的前兩個迭代中提供此函數,返回x
,即我們正在使用其方法函數的實例。 然后reduce()
將重復調用.union()
方法,並要求它從sequences
中獲取x
和下一個iterable的並集。 由於.union()
方法可能足夠聰明,可以注意到它被要求使用自己的實例獲取聯合而不需要做任何工作,因此調用x.union(x, some_iterable)
速度應該同樣快。至於只調用x.union(some_iterable)
。 最后, reduce()
將返回x
,我們有我們想要的集合。
這對我的個人品味來說有點棘手。 我不得不考慮這一點來理解它,而itertools.chain()
解決方案立即對我有意義。
編輯:@agf使它不那么棘手:
return sorted(reduce(set.union, sequences, set()))
這樣做要簡單易懂! 如果我們再次通過名稱x
調用set()
返回的實例(就像上面一樣,理解我並不是聲稱Python會將名稱x
與此實例綁定); 如果我們使用名稱n
來引用sequences
每個“下一個”值; 然后reduce()
將重復調用set.union(x, n)
。 當然,這與x.union(n)
完全相同。 恕我直言,如果你想要一個reduce()
解決方案,這是最好的解決方案。
-
如果你想要快速,請問自己:我們有什么方法可以將itertools
應用於此嗎? 有一個很好的方法:
from itertools import chain
return sorted(set(chain(*sequences)))
用*sequences
調用的itertools.chain()
用於將列表列表“展平”為單個可迭代。 這有點棘手,但只是一點點,這是一個常見的習語。
編輯:正如@Jbernardo在最流行的答案中所寫,並且正如@agf在注釋中所觀察到的, itertools.chain()
返回一個具有.from_iterable()
方法的對象,文檔說它會懶惰地評估迭代。 *
表示法強制構建一個列表,如果可迭代是一個長序列,它可能會占用大量內存。 實際上,你可以擁有一個永無止境的生成器,並且使用itertools.chain().from_iterable()
,只要你想運行你的程序就可以從中提取值,而*
表示法只會運行記不清。
正如@Jbernardo所寫:
sorted(set(itertools.chain.from_iterable(sequences)))
這是最好的答案,我已經對它進行了投票。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.