2014-03-14 57 views
3

最快(& python)方式來獲取不包含任何其他元素作爲其前綴的元素列表。Python:從列表中刪除元素作爲前綴的其他

(元素可以按任意順序排列,爲了清楚的解釋元素着想保持一種連續的在這裏,所以如果需要排序,必須明確地做)

輸入是

['AB', 'ABC', 'ABCDEF', 'ABCDEFG', 'BCD', 'DEF', 'DEFGHI', 'EF', 'GKL', 'JKLM'] 

元素淘汰:

'AB' prefix of 'ABC' 
'ABC' prefix of 'ABCDEF' 
'ABCDEF' prefix OF 'ABCDEFG' 
'DEF' prefix of 'DEFGHI' 

預期輸出

['ABCDEFG', 'BCD', 'DEFGHI', 'EF', 'GKL', 'JKLM'] 

被修改

增加了一點複雜度(或透明度)。列表的平均長度從500變化 - 900

+1

是否在輸出順序回事? – thefourtheye

+0

是的,結果必須排序。 – NEB

+0

您的輸出應該包含「ABCDEFG''和」DEFGHI''嗎?你的意思是你應該刪除其他人的前綴? –

回答

1

如果你的列表進行排序,每一個元素是一個前綴下一個,或者不是其中任何一個的前綴。因此,你可以這樣寫:

ls.sort() 
[ls[i] for i in range(len(ls))[:-1] if ls[i] != ls[i+1][:len(ls[i])]] + [ls[-1]] 

這將是n log(n)分揀加一次通過列表(n)。

對於您當前的排序列表,它也稍微快一點,因爲它是線性的,timeit給出了2.11 us。

稍微更快的實現(但不是漸近),並且更Python以及使用zip

[x for x, y in zip(ls[:-1], ls[1:]) if x != y[:len(x)]] + [ls[-1]] 

timeit給我們1.77

+0

對於我想這裏的樣本數據,第一個答案看起來相當快。 – NEB

+0

@NEB好吧,這就是我的時間顯示... – sashkello

+0

你說得對。我在900的平均列表長度上再次進行了採樣。拉鍊邏輯(700us)所花費的1000個循環的平均時間比第一個邏輯(740us)要好得多。感謝您的解決方案:) – NEB

1

列表理解(ls是您的輸入列表的名稱):我懷疑它在性能方面的最快

[x for x in ls if x not in [y[:len(x)] for y in ls if y != x]] 

,但這個想法非常簡單。您將逐個查看list元素,並檢查它是否是所有其餘元素列表中任何元素的前綴。

timeit結果:11.9我們每個循環(雖然縮放更重要的,如果你要使用它的大名單)

+1

除非你非常喜歡列表理解,否則不是「一個簡單的想法和可讀性」。它可以忍受一些解釋。 – Emmet

+0

@Emmet是的,同意,編輯... – sashkello

+0

@Emmet:這是我到目前爲止使用的解決方案,但每個循環所花費的平均時間大約爲240ms。 1000循環700us比1循環240ms好得多(代碼關鍵路徑中的性能增強非常好)。但我仍然同意你的想法和可讀性。 – NEB

0

ls.sort()第一,如果你的名單原本是無序的。

使用startswith

In [71]: [i for i, j in zip(ls[:-1], ls[1:]) if not j.startswith(i)]+[ls[-1]] 
Out[71]: ['ABCDEFG', 'BCD', 'DEFGHI', 'EF', 'GKL', 'JKLM'] 

enumerate

[v for i, v in enumerate(ls[:-1]) if not ls[i+1].startswith(v)]+[ls[-1]] 

與@ sashkello的做法相比:

In [78]: timeit [v for i, v in enumerate(ls[:-1]) if not ls[i+1].startswith(v)]+[ls[-1]] 
10000 loops, best of 3: 29.6 us per loop 

In [79]: timeit [i for i, j in zip(ls[:-1], ls[1:]) if not j.startswith(i)]+[ls[-1]] 
10000 loops, best of 3: 28.5 us per loop 

In [80]: timeit [x for x in ls if x not in [y[:len(x)] for y in ls if y != x]] 
1000 loops, best of 3: 1.77 ms per loop 
+0

你只是比較鄰居。 OP指定輸入可能未排序。 – roippi

+0

@roippi只需'ls.sort'就足夠了,我認爲;) – zhangxaochen

+0

是的,但你離開了時間。即使你更新它們,排序預先排序的列表顯然不代表現實生活中的表現。與sashkello的O(n ** 2)相比,您的算法複雜性*爲* O(nlogn),但此示例數據中的任何時間都不會接近真實的代表。 – roippi