Hapus semua kemunculan nilai dari daftar?

378

Dalam Python remove()akan menghapus nilai kemunculan pertama dalam daftar.

Bagaimana cara menghapus semua kemunculan suatu nilai dari daftar?

Inilah yang ada dalam pikiran saya:

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

Jawaban:

506

Pendekatan fungsional:

Python 3.x

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

atau

>>> 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]
Mark Rushakoff
sumber
120
Gunakan pemahaman daftar di atas filter + lambda; yang pertama lebih mudah dibaca selain umumnya lebih efisien.
habnabit
17
s / umumnya / umumnya menjadi /
habnabit
99
Kode untuk saran habnabit terlihat seperti ini:[y for y in x if y != 2]
coredumperror
8
Saya tidak akan menyebut solusi ini yang terbaik. Pemahaman daftar lebih cepat dan lebih mudah dipahami saat membaca kode. Ini lebih suka menjadi cara Perl daripada Python.
Peter Nimroot
3
-1 untuk memohon secara langsung __ne__. Membandingkan dua nilai adalah proses yang jauh lebih kompleks dari sekadar menelepon __eq__atau __ne__salah satunya. Ini mungkin berfungsi dengan benar di sini karena Anda hanya membandingkan angka, tetapi dalam kasus umum itu tidak benar dan bug.
Aran-Fey
212

Anda dapat menggunakan pemahaman daftar:

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]
mhawke
sumber
7
Bagaimana Anda menghapus item tanpa memeriksanya?
Alexander Ljungberg
18
Ini tidak mengubah daftar asli tetapi mengembalikan daftar baru.
John Y
6
@ Selelinap: Tidak, ini optimal karena hanya memindai daftar sekali. Dalam kode asli Anda, inoperator dan removemetode memindai seluruh daftar (hingga mereka menemukan kecocokan) sehingga Anda akhirnya memindai daftar beberapa kali dengan cara itu.
John Kugelman
4
@ mhawke, @ John Y: cukup gunakan x [:] = ... bukan x = dan itu akan menjadi "di tempat" daripada hanya mengubah nama 'x' (kecepatan pada dasarnya sama dan JAUH lebih cepat dari x .menghapus bisa !!!).
Alex Martelli
10
Saya memilih ini karena setelah 6 tahun Python saya masih tidak mengerti Lambdas :)
Benjamin
107

Anda dapat menggunakan penugasan slice jika daftar asli harus diubah, sementara masih menggunakan pemahaman daftar yang efisien (atau ekspresi generator).

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]
A. Coady
sumber
1
@ Selelinap: filter tidak mengubah daftar, itu mengembalikan daftar baru.
EM
filter dan daftar pemahaman tidak mengubah daftar. tugas irisan tidak. dan contoh aslinya tidak.
A. Coady
7
Saya suka ini karena ia memodifikasi daftar yang merujuk x. Jika ada referensi lain ke daftar itu, mereka akan terpengaruh juga. Ini berbeda dengan x = [ v for v in x if x != 2 ]proposal, yang membuat daftar baru dan mengubah x untuk merujuk padanya, membuat daftar asli tidak tersentuh.
Hannes
40

Mengulangi solusi posting pertama dengan cara yang lebih abstrak:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]
pengecut
sumber
19
Tapi O (n * n).
Hannes
@ Henry bukankah itu O (n) karena akan melalui loop sekali saja & pada saat yang sama menghapus item?
penta
1
Pertimbangkan x = [1] * 10000 + [2] * 1000. Badan loop dijalankan 1000 kali dan .remove () harus melewati 10000 elemen setiap kali dijalankan. Baunya seperti O (n * n) bagi saya tetapi tidak ada bukti. Saya pikir buktinya adalah mengasumsikan bahwa jumlah 2s dalam daftar sebanding dengan panjangnya. Faktor proporsionalitas itu kemudian menghilang dalam notasi O-besar. Namun, kasus terbaik hanya dari jumlah konstan 2s dalam daftar, bukan O (n ^ 2), hanya O (2n) yang merupakan O (n).
Hannes
23

Lihat solusi sederhana

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

Ini akan mengembalikan daftar yang memiliki semua elemen xtanpa2

Shameem
sumber
11

Semua jawaban di atas (selain dari Martin Andersson) membuat daftar baru tanpa item yang diinginkan, daripada menghapus item dari daftar asli.

>>> 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

Ini bisa menjadi penting jika Anda memiliki referensi lain ke daftar yang berkeliaran.

Untuk mengubah daftar di tempat, gunakan metode seperti ini

>>> 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

Sejauh menyangkut kecepatan, hasil pada laptop saya (semua ada di daftar entri 5000 dengan 1000 entri dihapus)

  • Pemahaman daftar - ~ 400us
  • Filter - ~ 900us
  • .remove () loop - 50ms

Jadi loop .Hapus sekitar 100x lebih lambat ........ Hmmm, mungkin pendekatan yang berbeda diperlukan. Yang tercepat yang saya temukan adalah menggunakan pemahaman daftar, tetapi kemudian mengganti konten dari daftar asli.

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace () - 450us
Paul S
sumber
Mengapa tidak menugaskan kembali daftar baru di bawah alamat lama? def remove_all(x, l): return [y for y in l if y != x]lalul = remove_all(3,l)
Dannid
@Dannid Itulah metode kedua dalam kotak kode pertama. Itu membuat daftar baru, dan Anda tidak mengubah daftar lama. Referensi lain ke daftar akan tetap tanpa filter.
Paul S
Ah benar Saya begitu terjebak dalam mendefinisikan metode, saya mengabaikan tugas sederhana yang sudah Anda lakukan.
Dannid
7

kamu bisa melakukan ini

while 2 in x:   
    x.remove(2)
Amr
sumber
3
Itu solusi yang buruk, karena daftar harus dilalui 2 * n kali untuk n kejadian 2.
cxxl
Tidak disarankan untuk menambah atau menghapus dari daftar yang Anda lalui. IMHO praktik buruk.
Aman Mathur
5

Dengan biaya keterbacaan, saya pikir versi ini sedikit lebih cepat karena tidak memaksa sementara untuk memeriksa ulang daftar, sehingga melakukan pekerjaan yang persis sama harus dilakukan:

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)
Martin Andersson
sumber
Untuk daftar yang Anda tunjukkan dalam kode Anda, pendekatan ini sekitar 36% lebih lambat daripada metode pemahaman daftar (yang mengembalikan salinan), menurut pengukuran saya.
djsmith
Bagus Anda memperhatikan itu. Namun, karena saya pikir itu mungkin melemahkan penilaian Anda, saya membandingkan versi saya dengan proposal pertama yang dibuat oleh penulis pertanyaan.
Martin Andersson
4

Pendekatan dan pengaturan waktu yang kasar terhadap daftar / array dengan 1.000.000 elemen:

Pengaturan waktu:

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

Kesimpulan: numpy 27 kali lebih cepat (di notebook saya) dibandingkan dengan pendekatan daftar pemahaman

PS jika Anda ingin mengonversi daftar Python biasa Anda lstmenjadi array numpy:

arr = np.array(lst)

Mendirikan:

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

Memeriksa:

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

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949
MaxU
sumber
4
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

Mungkin bukan yang paling pythonic tapi tetap yang paling mudah bagi saya haha

Ankit Sharma
sumber
3

Untuk menghapus semua kejadian duplikat dan meninggalkan satu di daftar:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

Berikut adalah fungsi yang saya gunakan untuk Project Euler:

def removeOccurrences(e):
  return list(set(e))
Jared Burrows
sumber
2
Saya perlu melakukan ini pada vektor dengan nilai 250k, dan itu berfungsi seperti pesona.
rschwieb
1
Jawabannya iya! Dan saya benar-benar mengerti jika memiliki vektor yang lama kedengarannya benar-benar gila untuk seorang programmer yang kompeten. Saya mendekati masalah di sana sebagai ahli matematika, tidak khawatir tentang mengoptimalkan solusi, dan itu dapat menyebabkan solusi lebih lama dari par. (Meskipun saya tidak punya kesabaran untuk solusi lebih dari 5 menit.)
rschwieb
6
Ini akan menghapus pemesanan apa pun dari daftar.
penanggung jawab
4
@JaredBurrows mungkin karena tidak menjawab pertanyaan seperti saat ini, tetapi pertanyaan yang sangat berbeda.
drevicko
6
-1, ini bukan jawaban untuk pertanyaan OP. Ini adalah solusi untuk menghapus duplikat, yang merupakan masalah yang sama sekali berbeda.
Anoyz
2

Saya percaya ini mungkin lebih cepat daripada cara lain jika Anda tidak peduli tentang urutan daftar, jika Anda berhati-hati tentang pesanan akhir, simpan indeks dari aslinya dan gunakan itu.

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]
Michael Clemmons
sumber
2
Saya mengerti ke mana tujuan Anda, tetapi kode ini tidak akan berfungsi karena Anda juga memerlukan indeks awal dan bukan hanya 0.
Shedokan
2
for i in range(a.count(' ')):
    a.remove(' ')

Jauh lebih sederhana, saya percaya.

marco
sumber
2
harap edit jawaban Anda untuk meningkatkan kejelasan. Harap jelaskan apa sebenarnya yang direkomendasikan oleh kode Anda, mengapa ia bekerja dan mengapa ini adalah rekomendasi Anda. Harap juga memformat pertanyaan Anda dengan benar sehingga kode dapat dilihat dengan jelas dari sisa jawaban Anda.
Ortund
2

Membiarkan

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

Solusi paling sederhana dan efisien seperti yang sudah diposting sebelumnya adalah

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

Kemungkinan lain yang harus menggunakan memori lebih sedikit tetapi lebih lambat adalah

>>> 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]

Waktu hasil untuk daftar panjang 1000 dan 100000 dengan entri yang cocok 10%: 0,16 vs 0,25 ms, dan 23 vs 123 ms.

Pengaturan waktu dengan panjang 1000

Pengaturan waktu dengan panjang 100000

Jolvi
sumber
1

Hapus semua kemunculan nilai dari daftar Python

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()

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

Kalau tidak,

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)

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

rafiqul786
sumber
"Python 'bersarang untuk setiap loop jika' dalam fungsi yang bekerja dengan akurasi 100%!"
rafiqul786
Anda tidak mengubah daftar Anda hanya mencetak elemen. Juga menyebutkan daftar sebagai daftar membingungkan
kon psych
0

Jika Anda tidak memiliki built-in filteratau tidak ingin menggunakan ruang tambahan dan Anda memerlukan solusi linier ...

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]
sandi
sumber
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

['Halo Dunia']

SaNaMeDiO
sumber
coba uraikan jawaban Anda dengan penjelasan.
parlad
0

Saya hanya melakukan ini untuk daftar. Saya hanyalah seorang pemula. Seorang programmer yang sedikit lebih maju pasti dapat menulis fungsi seperti ini.

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

Kami juga dapat melakukan di tempat menghapus semua menggunakan salah satu delatau pop:

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))

Sekarang untuk efisiensi:

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

Seperti yang kita lihat bahwa versi in-place remove_values_from_list()tidak memerlukan memori tambahan, tetapi itu membutuhkan lebih banyak waktu untuk berjalan:

  • 11 detik untuk inplace menghapus nilai
  • 710 mili detik untuk pemahaman daftar, yang mengalokasikan daftar baru dalam memori
tuxdna
sumber
0

Tidak ada yang memposting jawaban optimal untuk kompleksitas waktu dan ruang, jadi saya pikir saya akan mencobanya. Berikut adalah solusi yang menghapus semua kemunculan dari nilai tertentu tanpa membuat array baru dan pada kompleksitas waktu yang efisien. Kekurangannya adalah bahwa unsur-unsur tidak menjaga ketertiban .

Kompleksitas waktu: O (n)
Kompleksitas ruang tambahan: 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()
Josh
sumber
-1

Soal kecepatan!

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
Sergey Kozlovskiy
sumber
-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

Hanya dengan Python 3

pengguna5064329
sumber
2
Meriah, ini berada dalam ruang lingkup pertanyaan yang diajukan dan benar.
Erich
Saya tidak melihat bagaimana itu benar. Ini akan menghapus semua item dari daftar, tidak semua kemunculan nilai .
Georgy
-3

Ada apa dengan:

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

Menggunakan anaconda

pengembang kode
sumber
2
Tolong jelaskan baris kode Anda sehingga pengguna lain dapat memahami fungsinya. Terima kasih!
Ignacio Ara
Kode ini tidak akan menghapus apa pun dari daftar.
Georgy