標籤:

Python 中如何刪除一個列表 List 中多個符合條件的元素?

假設有一個列表:

a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6]

判斷如果a列表中元素"2"前面的一個元素是"0",那麼刪除這個元素"0",請問該如何操作?


[x[0] for x in zip(a,a[1:]+[None]) if x!=(0,2)]

又:注意其他答案有些不能處理len(a) in [0,1]的情形


典型的reduce問題…

from functools import reduce

a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6]

def reducer(acc, y):
if acc and acc[-1] == 0 and y == 2:
acc.pop()
acc.append(y)
return acc

result = reduce(reducer, a, [])
assert result == [1, 1, 2, 0, 0, 8, 3, 2, 5, 2, 6]

這個方案,2前面如果有多個0,只會刪除1個0(比較符合題主的意思)。但是如果需要刪除多個0,就需要pop多次了:

from functools import reduce

a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 0, 2, 6]

def reducer(acc, y):
if y == 2:
while acc and acc[-1] == 0:
acc.pop()
acc.append(y)
return acc

result = reduce(reducer, a, [])
assert result == [1, 1, 2, 0, 0, 8, 3, 2, 5, 2, 6]


def foo(a):
n = 0
for e in a:
if e == 0:
n += 1
elif e == 2:
n = 0
yield 2
else:
for i in range(n): yield 0
n = 0
yield e
for i in range(n): yield 0

print(list(foo([0]))) # 0
print(list(foo([1]))) # 1
print(list(foo([0, 1]))) # 0 1
print(list(foo([0, 2]))) # 2
print(list(foo([0, 2, 0]))) # 2 0
print(list(foo([0, 0, 2, 0]))) # 2 0
print(list(foo([0, 0, 0, 2, 0]))) # 2 0
print(list(foo([1, 0, 0, 0, 2, 0]))) # 1 2 0
print(list(foo([1, 0, 0, 0, 2, 0, 2]))) # 1 2 2

這種問題還要什麼fp,要什麼遞歸……


python中個人感覺filter函數是正解。畢竟有函數不用卻自己寫循環不符合寫程序懶惰的特質

比如list中去空字元(配合lambda表達式):

condition = lambda t: t != "" (判斷符合條件很複雜就不能使用lambda,自己寫方法吧)

filter_list = list(filter(condition, list)


a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6]
for i in range(0,len(a)-2):
if(a[i]==0 and a[i+1]==2):
del(a[i])
i=i-1
a
[1, 1, 2, 0, 0, 8, 3, 2, 5, 2, 6]


想了很多方法,終於找到一個感覺比較好的

a = [1, 2, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6, 1, 2]

可以找出每個符合條件的"0"的索引值i,但是如果直接用del[i]刪除此元素,會導致列表的索引值發生改變,按照原來的索引值刪除就會出錯,比較好的做法是:

to_delete = []
for i,item in enumerate(a):
if item == 2:
if a[i-1] == 0:
to_delete.append(i-1)
a_new = [item for i,item in enumerate(a) if i not in to_delete]

結果

[1, 2, 1, 2, 0, 0, 8, 3, 2, 5, 2, 6, 1, 2]


for i in range(len(a)-1,-1,-1):
if a[i]==0 and a[i+1]==2:
a.pop(i)

參考了python幫助文檔里去除list中重複字元的代碼。我也是剛學習python,剛起步,看到了忍不住聯繫一下。


l = [l[i] for i in filter(lambda i: l[i] !=0 or i == len(l) or l[i+1] != 2, range(len(l)))]


如果真的是你這樣的數據…變字元串join起來把所有的02變成2不就好了?


底下六種方式都可以解:a= [0,2,0,0,200,0,20,22,0,2,222,0,0,20,0,0,0,2,0,2]的問題

如果認真想的話應該還有許多方式,有興趣的人可以嘗試。

——————————————————————————

第一種方式:

y=[a.pop(i) for i in range(len(a)) if a[i:i+2]==[0,2]]

print(a)

——————————————————————————

第二種方式:

如果a的長度是單數 需要在a的後面+[0] 然後 print(eval(y)[:-1])

z=iter(a)

y=re.sub("[()]","",str([(x,next(z)) for x in z]).replace("(0, 2)","2"))

print(eval(y))

——————————————————————————

第三種方式:

for i in range(len(a)):

try:

if str(a[i])+str(a[i+1])=="02":

del a[i]

except Exception as e:

break

print(a)

——————————————————————————

第四種方式:

————————————————————————————————————

第五種方式:

y=iter(a+[0])

print(next(y))

b=list(filter(lambda x:x+(next(y)/100)!=0.02,a))

print(b)

—————————————————————————————————————

第六種方式:

#如果a長度是雙數

k=[]

for x,y in zip(a[::2],a[1::2]):

if [x,y] == [0, 2]:

k.extend([y])

else:

k.extend([x,y])

print(k)

#如果a長度是單數

a+=[0]

k=[]

for x,y in zip(a[::2],a[1::2]):

if [x,y] == [0, 2]:

k.extend([y])

else:

k.extend([x,y])

print(k[:-1])

——————————————————————————————————


我先聲明我也是剛學習Python的,這個問題我獻醜一下吧。

功能應該能實現,但是如果考慮代碼簡潔程度或者效率,還是坐等更高明的答案了。

def remove_1(lst):
ans = []
for i in range(len(lst)):
if lst[i] == 0:
try:
if lst[i+1] == 2: pass
else: ans.append(lst[i])
except: ans.append(lst[i])
else: ans.append(lst[i])
return ans


# 刪除列表中連續重複項,for遍歷會出錯,解決方法就是把需要的數據放到新的列表中

# 方法1 放在空的列表中

list1 = [1, 1, 2, 2, 3, 4, 17, 17, 23, 45, 23, 23, 13, 13, 36]

list2 = []

for i in list1:

if i &> 18:

list2.append(i)

print(list2)

# 利用列表表達式生成新的列表

list1 = [1, 1, 2, 2, 3, 4, 17, 17, 23, 45, 23, 23, 13, 13, 36]

list3 = [i for i in list1 if i &> 18]

print(list3)

# 方法3:利用filter和lambda函數生成新的列表

list1 = [1, 1, 2, 2, 3, 4, 17, 17, 23, 45, 23, 23, 13, 13, 36]

list4 = list(filter(lambda x : x &> 18, list1))

print(list4)


print
(lambda l:
(lambda f, l: f(f, l))
(lambda f, l: l and l[0:1] if len(l) &< 2 else (f(f, l[1:]) if l[0] == 0 and l[1] == 2 else l[0:1] + f(f, l[1:])), l) )(a)


用filter函數


[a[i] for i in range(len(a)) if a[i]!= 0 or i+1==len(a) or a[i+1] != 2]


唉。。。我很無聊啊。。。樓上就沒有一個對的。。。就算拿著list comprehension來搗鼓,或者拿著接近FP的lambda來搗鼓了也得先把題目搞清楚啊。。。那位用lambda的,也至少得再加上一個不動點子嘛~,

==== 你們的錯在於如果遇到

a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 0, 2, 6]

你們的output就是:

[1, 1, 2, 0, 0, 8, 3, 2, 5, 0, 2, 6]

這個結果顯然不對啊,所以說,引入iteration很重要。

--------

最近順手就寫個lisp版本吧。。。反正改過去就是個遞歸而已沒差別了

(define (match-pattern list)
(cond ((null? list) 0)
((and (eq? 0 (car list)) (eq? 2 (cadr list))) (+ 1 (match-pattern (cdr list))))
(else (+ 0 (match-pattern (cdr list))))))
(define (delete-pattern list)
(define (delete list)
(cond ((null? list) "())
((and (eq? 0 (car list)) (eq? 2 (cadr list))) (cons 2 (delete (cddr list))))
(else (cons (car list) (delete (cdr list))))))
(define (iter-delete list)
(if (= 0 (match-pattern list))
list
(iter-delete (delete list))))
(iter-delete list))

Output:

(define b (list 1 1 0 2 0 0 8 3 0 2 5 0 0 2 6))
(delete-pattern b)

;=&> (1 1 2 0 0 8 3 2 5 2 6)

(define a (list 1 1 0 2 0 0 8 3 0 2 5 0 2 6))
(delete-pattern a)
;=&> (1 1 2 0 0 8 3 2 5 2 6)


一般不建議在原列表上面直接操作,最好是新生成一個列表

&>&>&> a = [1, 1, 0, 2, 0, 0, 8, 3, 0, 2, 5, 0, 2, 6]
&>&>&> b = [a[i] for i in range(0, len(a) - 1) if not ( a[i] == 0 and a[i+1] == 2 )]
&>&>&> b.append(a[-1])
[1, 1, 2, 0, 0, 8, 3, 2, 5, 2, 6]


用filter配合lambda表達式豈不是美滋滋?


a=[a[i] for i in range(len(a)) if not(a[i]==0 and a[i+1]==2)]


做一個判斷來看產生新列表裡面是否還存在符合條件的元素,如果有則要繼續刪除,參考了樓上匿名用戶的代碼

PS:我剛開始學python,這個程序其實效率很低下,有沒有更高效一點的,求指導~

a=3,2,1,6,5,0,2,1,3,5,0,2,1,2,0,0,0,2,3,6,5,2,2
while(filter(lambda i:a[i]==0 and a[i+1]==2,range(len(a)-1))):
a=[a[i] for i in filter(lambda i:a[i]!=0 or i==len(a) or a[i+1]!=2,range(len(a)))]


推薦閱讀:

被代碼佔領的世界會是什麼樣?
怎樣用 Matlab 寫出優雅的代碼?
opencv庫的python版為啥比c++版小這麼多?是功能有區別嗎?
如何用 Python 中的 NLTK 對中文進行分析和處理?
用python去搞數學建模可行性大不大?

TAG:Python |