2012-10-01 36 views
10

如果匹配子字符串,我如何從列表中刪除元素?從匹配子字符串的列表中刪除項目 - Python

我曾嘗試使用pop()enumerate方法從列表中移除元素,但好像我缺少需要刪除一些相鄰的項目:

sents = ['@$\tthis sentences needs to be removed', 'this doesnt', 
    '@$\tthis sentences also needs to be removed', 
    '@$\tthis sentences must be removed', 'this shouldnt', 
    '# this needs to be removed', 'this isnt', 
    '# this must', 'this musnt'] 

for i, j in enumerate(sents): 
    if j[0:3] == "@$\t": 
    sents.pop(i) 
    continue 
    if j[0] == "#": 
    sents.pop(i) 

for i in sents: 
    print i 

輸出:

this doesnt 
@$ this sentences must be removed 
this shouldnt 
this isnt 
#this should 
this musnt 

所需的輸出:

this doesnt 
this shouldnt 
this isnt 
this musnt 
+3

經常從列表中刪除項目,而您正在迭代該列表。閱讀與此相關的其他數十個Stack Overflow問題。另請參閱[文檔中的註釋](http://docs.python.org/reference/compound_stmts.html#for)。 –

+1

您應該始終避免在迭代容器時更改容器的長度,這是容災 – wim

+0

通常,創建新的過濾列表通常比嘗試就地修改列表更好。不可變的算法總是比較容易理解(雖然並不總是比較容易理解如何編寫)。當你只是替換值時,有時候就地工作的效率提高了,但是當你刪除或插入列表的中間時,通常會獲得_worse_效率以及不太穩健的邏輯。 – abarnert

回答

20

如何ABO UT一些東西:

>>> [x for x in sents if not x.startswith('@$\t') and not x.startswith('#')] 
['this doesnt', 'this shouldnt', 'this isnt', 'this musnt'] 
+0

啊一個列表修真,優雅!讓我嘗試。 – alvas

+0

+1爲最乾淨的答案。 – abarnert

8

這應該工作:

[i for i in sents if not ('@$\t' in i or '#' in i)] 

如果你想只有那些指定的開始句使用使用str.startswith(stringOfInterest)方法

+2

我認爲這一個比另外兩個更好,因爲沒有假設子字符串在開始 – Frikster

9

另一種技術的東西filter

filter(lambda s: not (s[0:3]=="@$\t" or s[0]=="#"), sents) 

您的orignal approac的問題h是當您列出項目i並確定它應該被刪除時,您將其從列表中移除,將i+1項目滑入i位置。循環的下一個迭代,您在索引i+1,但該項目實際上是i+2

有意義嗎?

+0

感謝您的解釋!枚舉時彈出列表確實很愚蠢。哈哈哈.. – alvas

+0

+1用於解釋問題。 – abarnert