2011-08-04 80 views
5

只有噹噹前迭代元素不在列表中時,我必須將元素附加到列表中。這裏列表理解是否合適?

>>> l = [1, 2] 
>>> for x in (2, 3, 4): 
...  if x not in l: 
...    l.append(x) 
... 
>>> l 
[1, 2, 3, 4] 

VS

>>> l = [1, 2] 
>>> [l.append(i) for i in (2, 3, 4) if i not in l] 
[None, None] 
>>> l 
[1, 2, 3, 4] 

列表內涵給出結果就是我想要的,只是返回的列表是沒用的。這是列表解析的一個很好的用例嗎?

迭代是一個很好的解決方案,但我想知道是否有更習慣的方式來做到這一點?

+0

出於某種原因,我無法再次編輯我的問題。我忘了說我關心元素的順序。 – Paolo

+0

在日常使用中,我必須在所提出的解決方案之間進行調解。 Gerrat的結構緊湊,TokenMacGuy的外觀和速度都很快,而Tyz的位置中間,緊湊而快速,但不那麼直接。感謝偉大的答案。我檢查了格拉特答案,因爲它更接近我原來的意圖。 – Paolo

回答

5

你可以這樣做:

l.extend((i for i in (2,3,4) if i not in l)) 

這個解決方案仍然有效,如果添加的列表是唯一的。

+0

當要附加的數字不唯一時,此代碼將得到不同的結果。如:(2,3,4,4) – HYRY

+0

@ user772649:如果這是一種可能性,那麼簡單地在要添加的數字組周圍環繞一個'set'就可以解決這個問題。 – Gerrat

+0

如果位置信息不重要,則使用set()。 set()將改變序列的順序。 – HYRY

3

不鼓勵使用僅用於副作用的列表推導。 3線版本沒有任何問題。

如果l變得非常長,則可能需要並行地維護一組,以避免一長串

7

這種算法使用in l,有或者沒有一個列表理解,是不是儘可能高效; list.__contains__是O(n),因此將另一個列表的元素添加到O(n )。另一方面,set.__contains__是O(log n),所以最好的做法是使用一個集來檢查成員資格,並使用一個列表來保存順序。這樣你就可以進行n次操作,即O(log n),總共爲O(n log n),對於n的合理值(高於100個元素),這比O(n )快得多, 。

>>> l = [1, 2] 
>>> seen = set(l) 
>>> for x in (2, 3, 4): 
...  if x not in seen: 
...   seen.add(x) 
...   l.append(x) 
... 
>>> l 
[1, 2, 3, 4] 
>>> 
+0

+1算法規範 – Kracekumar

3

我可以建議一個更解決方案:

orig = [1,2] 
ext = [2,3,4] 
orig.extend(filter(lambda x,p=set(orig):not(x in p or p.add(x)),ext)) 

它考慮到元素的順序和元素的重複的情況下工作。

順便提一下,複雜度是O(n * log(n))。

+0

過度聰明,無論如何+1。 – SingleNegationElimination