Listeden bir değerin tüm tekrarları kaldırılsın mı?


377

Python remove()bir listedeki değerin ilk oluşumunu kaldıracak.

Listeden bir değerin tüm tekrarları nasıl kaldırılır ?

Aklımda olan şey bu:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]

Yanıtlar:


505

Işlevsel yaklaşım:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

veya

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]

120
Filtre + lambda üzerinde liste kavrayışı kullanın; ilki genel olarak daha verimli olmasına ek olarak daha okunabilir.
habnabit

17
s / genellikle / genel olarak olmak /
habnabit

99
Habnabit'in önerisinin kodu şuna benziyor:[y for y in x if y != 2]
coredumperror

8
Bu çözümü en iyi olarak adlandırmam. Kod aracılığıyla gözden geçirirken liste kavrayışlarını anlamak daha hızlı ve kolaydır. Bu, Python'dan daha çok bir Perl yolu olacaktır.
Peter Nimroot

3
Doğrudan çağırmak için -1 __ne__. İki değeri karşılaştırmak, sadece birini çağırmaktan __eq__veya __ne__bunlardan birini kullanmaktan çok daha karmaşık bir süreçtir . Burada doğru çalışabilir, çünkü sadece sayıları karşılaştırıyorsunuz, ancak genel durumda bu yanlış ve bir hata.
Aran-Fey

211

Bir liste kavrayışı kullanabilirsiniz:

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]

7
Öğeleri kontrol etmeden nasıl kaldırabilirsiniz?
Alexander Ljungberg

18
Bu, orijinal listeyi değiştirmez, ancak yeni bir liste döndürür.
John Y

6
@Selinap: Hayır, listeyi yalnızca bir kez taradığı için bu en uygunudur. Orijinal kodunuzda, hem inoperatör hem de removeyöntem listenin tamamını tarar (bir eşleşme buluncaya kadar), böylece listeyi bu şekilde birden çok kez tararsınız.
John Kugelman

4
@mhawke, @John Y: x = yerine x [:] = ... kullanın ve 'x' ismini yeniden hatırlatmak yerine "yerinde" olacaktır (hız aslında aynıdır ve x'ten çok daha hızlıdır) . çıkarma olabilir !!!).
Alex Martelli

10
Bunu oyluyorum çünkü 6 yıl Python'dan sonra hala Lambdas'ı anlamıyorum :)
Benjamin

107

Orijinal listenin değiştirilmesi gerekiyorsa, yine de verimli bir liste kavrama (veya üretici ifadesi) kullanırken dilim atamasını kullanabilirsiniz.

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]

1
@Selinap: filtre listeyi değiştirmez, yeni bir liste döndürür.
EM

filtre ve liste kavrayışları bir listeyi değiştirmez. dilim ataması yapar. ve orijinal örnek.
A. Coady

7
Bunu seviyorum çünkü x'in başvurduğu listeyi değiştiriyor. Bu listeye başka referanslar da varsa, bunlar da etkilenecektir. Bu, x = [ v for v in x if x != 2 ]yeni listeyi oluşturan ve orijinal listeye dokunmadan bırakarak x'i değiştirerek tekliflerin aksine .
Hannes

40

İlk gönderinin çözümünü daha soyut bir şekilde tekrarlamak:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]

19
Yine de O (n * n).
Hannes

@Hannes sadece bir kez ve aynı zamanda öğeyi kaldırarak döngüden geçtiği için O (n) olmaz mı?
penta

1
Düşünün x = [1] * 10000 + [2] * 1000. Döngü gövdesi 1000 kez yürütülür ve .remove () her çağrıldığında 10000 öğeyi atlamak zorundadır. Bu bana O (n * n) gibi kokuyor ama kanıt yok. Kanıt, listedeki 2'lerin sayısının uzunluğuyla orantılı olduğunu varsaymak olacaktır. Bu orantılılık faktörü büyük O gösterimlerinde kaybolur. Bununla birlikte, listede sadece sabit bir 2s sayısının en iyi durumu O (n ^ 2) değil, sadece O (n) olan O (2n) 'dir.
Hannes

23

Basit çözüme bakın

>>> [i for i in x if i != 2]

Bu, tüm öğelerine sahip xolmayan bir liste döndürür.2


11

Yukarıdaki tüm cevaplar (Martin Andersson'un dışında), orijinal listeden öğeleri kaldırmak yerine, istenen öğeler olmadan yeni bir liste oluşturur.

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

Bu, etrafta asılı kalan listeye başka referanslarınız varsa önemli olabilir.

Listeyi yerinde değiştirmek için böyle bir yöntem kullanın

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

Hız söz konusu olduğunda, dizüstü bilgisayarımdaki sonuçlar (tümü 1000 giriş kaldırılmış bir 5000 giriş listesinde)

  • Liste anlama - ~ 400us
  • Filtre - ~ 900us
  • .remove () döngüsü - 50 ms

Yani .remove döngüsü yaklaşık 100x daha yavaştır ........ Hmmm, belki farklı bir yaklaşım gereklidir. Bulduğum en hızlı şey, liste kavrayışını kullanmak, ancak orijinal listenin içeriğini değiştirmek.

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeeall_replace () - 450us

Neden yeni listeyi eski adresin altında yeniden atamıyorsunuz? def remove_all(x, l): return [y for y in l if y != x]sonral = remove_all(3,l)
Dannid

@Dannid Bu, ilk kod kutusundaki ikinci yöntemdir. Yeni bir liste oluşturur ve eski listeyi değiştirmezsiniz. Listeye yapılan diğer referanslar filtrelenmeden kalır.
Paul S

Ah doğru. Bir yöntemi tanımlarken çok yakalandım, daha önce yapmış olduğunuz basit ödevi göz ardı ettim.
Dannid

7

Bunu yapabilirsiniz

while 2 in x:   
    x.remove(2)

3
Bu kötü bir çözümdür, çünkü liste 2 kez 2 kez n * 2 kez
geçilmelidir

Geçmekte olduğunuz listeye ekleme veya listeden çıkarma önerilmez. Kötü uygulama IMHO.
Aman Mathur

5

Okunabilirlik pahasına, bu sürümü listeyi yeniden incelemek için zorlamadığı için biraz daha hızlı olduğunu düşünüyorum, böylece tam olarak aynı işi kaldırma yapmak zaten yapmak zorunda:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)

Kodunuzda gösterdiğiniz liste için bu yaklaşım, ölçümüme göre liste anlama yönteminden (bu bir kopya döndürür) yaklaşık% 36 daha yavaştır.
djsmith

İyi bunu fark ettin. Bununla birlikte, kararınızı atlamış olabileceğini düşündüğüm için, versiyonumu soru yazarı tarafından yapılan ilk teklifle karşılaştırıyordum.
Martin Andersson

4

1.000.000 eleman içeren bir liste / dizi ile ilgili numpy yaklaşımı ve zamanlamaları:

Zamanlamaları:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

Sonuç: Numpy, liste kavrama yaklaşımına kıyasla 27 kat daha hızlı (dizüstü bilgisayarımda)

PS, normal Python listenizi lstnumpy dizisine dönüştürmek istiyorsanız :

arr = np.array(lst)

Kurmak:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

Kontrol:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949

4
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

Belki de en pitonik değil ama yine de benim için en kolay haha


3

Tüm yinelenen olayları kaldırmak ve bir tanesini listede bırakmak için:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

İşte Project Euler için kullandığım fonksiyon:

def removeOccurrences(e):
  return list(set(e))

2
Bunu 250k değerleri olan bir vektörde yapmam gerekiyordu ve bir cazibe gibi çalışıyor.
rschwieb

1
Cevap Evet! Yetkili bir programcıya uzun çılgınca gelen bir vektöre sahip olup olmadığımı tamamen anlıyorum. Oradaki problemlere bir matematikçi olarak yaklaşıyorum, çözümleri optimize etmekten endişe etmiyorum ve bu da par'dan daha uzun çözümlere yol açabilir. (5 dakikadan uzun çözümler için sabrım olmamasına rağmen.)
rschwieb

6
Bu, siparişleri listeden kaldıracaktır.
asmeurer

4
@JaredBurrows belki de şu anda olduğu gibi soruyu cevaplamıyor, ancak oldukça farklı bir soru.
drevicko

6
-1, bu OP'nin sorusuna bir cevap değildir. Tamamen farklı bir konu olan kopyaları kaldırmak için bir çözümdür.
Anoyz

2

Eğer liste siparişi umurumda değilse, muhtemelen diğer herhangi bir yol daha hızlı olduğuna inanıyorum, son sipariş hakkında dikkat orijinal dizinleri saklamak ve bu tarafından başvurmak.

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]

2
Nereye gittiğini anlıyorum, ancak sadece 0'a değil, başlangıç ​​dizinine de ihtiyacınız olduğu için bu kod çalışmaz.
Shedokan

2
for i in range(a.count(' ')):
    a.remove(' ')

Çok daha basit olduğuna inanıyorum.


2
lütfen netliğinizi artırmak için cevabınızı düzenleyin. Lütfen önerilen kodunuzun tam olarak ne yaptığını, neden çalıştığını ve bunun neden öneriniz olduğunu açıklayın. Lütfen sorunuzu doğru şekilde biçimlendirin, böylece kod yanıtınızın geri kalanından açıkça anlaşılabilir.
Ortund

2

İzin Vermek

>>> x = [1, 2, 3, 4, 2, 2, 3]

Daha önce yayınlandığı gibi en basit ve verimli çözüm

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

Daha az bellek kullanması gereken ancak daha yavaş olması gereken bir diğer olasılık

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

% 10 eşleşen girişlerle 1000 ve 100000 uzunluklu listeler için zamanlama sonuçları: 0,16 vs 0,25 ms ve 23 vs 123 ms.

Uzunluk 1000 ile zamanlama

100000 uzunluğunda zamanlama


1

Bir değerin tüm tekrarlarını bir Python listesinden kaldırma

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

Sonuç: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Alternatif olarak,

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

Sonuç: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


"Python 'her if döngü için iç içe'% 100 doğrulukla çalışan bir işlev içinde!"
rafiqul786

Sadece öğeleri yazdırdığınız listeyi değiştirmezsiniz. Bir listeyi listeler olarak adlandırmak da kafa karıştırıcı
kon psych

0

Yerleşik filterveya ekstra alan kullanmak istemiyorsanız ve doğrusal bir çözüme ihtiyacınız varsa ...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]

0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['Selam Dünya']


lütfen cevabınızı açıklama ile detaylandırmaya çalışın.
parlad

0

Bunu sadece bir liste için yaptım. Ben sadece bir acemiyim. Biraz daha gelişmiş bir programcı kesinlikle böyle bir işlev yazabilir.

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break

0

Ayrıca, delveyapop :

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))

Şimdi verimlilik için:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

Bu yerinde sürümü gördüğümüz gibi remove_values_from_list() fazladan bellek gerektirmediğini , çalışması çok daha fazla zaman alıyor:

  • Yerinde kaldırma değerleri için 11 saniye
  • Hafızada yeni bir liste ayıran liste anlaşmaları için 710 mili saniye

0

Kimse zaman ve mekan karmaşıklığı için en uygun cevabı yayınlamadı, bu yüzden denemek istedim. Burada, yeni bir dizi oluşturmadan ve verimli bir zaman karmaşıklığında belirli bir değerin tüm oluşumlarını kaldıran bir çözüm bulunmaktadır. Dezavantajı, öğelerin düzeni korumamasıdır .

Zaman karmaşıklığı: O (n)
Ek alan karmaşıklığı: O (1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()

-1

Hız hakkında!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11

-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

Sadece Python 3 ile


2
Çok komik bir şekilde, bu soru sorulmakta ve doğrudur.
Erich

Nasıl doğru olduğunu anlamıyorum. Bu , bir değerin tüm örneklerini değil, tüm öğeleri listeden kaldırır .
Georgy

-3

Sorun ne:

Motor=['1','2','2']
For i in Motor:
       If i  != '2':
       Print(i)
Print(motor)

Anaconda kullanma


2
Diğer kullanıcıların işlevlerini anlayabilmesi için lütfen kod satırlarınızı açıklayın. Teşekkürler!
Ignacio Ara

Bu kod listeden hiçbir şey kaldırmaz .
Georgy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.