Видалити всі записи значення зі списку?


377

У Python remove()буде видалено перше виникнення значення зі списку.

Як видалити всіх події значення зі списку?

Це те, що я маю на увазі:

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

Відповіді:


505

Функціональний підхід:

Python 3.x

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

або

>>> 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
Використовуйте розуміння списку через фільтр + лямбда; перший є легшим для читання, крім загальноефективнішого.
ханабіт

17
s / взагалі / взагалі будучи /
habnabit

99
Код пропозиції ханабіта виглядає приблизно так:[y for y in x if y != 2]
coredumperror

8
Я б не назвав це рішення найкращим. Ознайомлення зі списком швидше і простіше зрозуміти під час перегляду коду. Це скоріше скоріше швидше Perl, ніж Python.
Пітер Німрут

3
-1 для прямого виклику __ne__. Порівняння двох значень є набагато складнішим процесом, ніж просто виклик __eq__або __ne__одне з них. Тут може працювати правильно, оскільки ви порівнюєте лише цифри, але в загальному випадку це неправильно і помилка.
Аран-Фей

211

Ви можете використати розуміння списку:

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
Як би ви видалили предмети, не перевіряючи їх?
Олександр Люнгберг

18
Це не змінює вихідний список, але повертає новий список.
Джон Y

6
@Selinap: Ні, це оптимально, оскільки він сканує список лише один раз. У вихідному коді і inоператор, і removeметод сканують весь список (до тих пір, поки вони не знайдуть відповідність), так що ви в кінцевому підсумку скануєте список кілька разів таким чином.
Джон Кугельман

4
@mhawke, @Jo Y: просто використовуйте x [:] = ... замість x = і це буде "на місці", а не просто перезаписувати ім'я "x" (швидкість по суті однакова і МНОГО швидша, ніж x .молодити можна !!!).
Алекс Мартеллі

10
Я проголосую за це, тому що після 6 років Python я досі не розумію Лямбда :)
Бенджамін

107

Ви можете використовувати призначення зрізів, якщо вихідний список повинен бути змінений, використовуючи при цьому ефективне розуміння списку (або вираз генератора).

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

1
@Selinap: фільтр не змінює список, він повертає новий список.
EM

Фільтр та розуміння списку не змінюють список. призначення зрізів робить. і оригінальний приклад так.
А. Коуді

7
Мені це подобається, оскільки він змінює список, на який посилається х. Якщо є якісь інші посилання на цей список, вони також будуть впливати. Це на відміну від x = [ v for v in x if x != 2 ]пропозицій, які створюють новий список і змінюють x для посилання на нього, залишаючи оригінальний список недоторканим.
Ганнес

40

Повторення рішення першого допису більш абстрактним чином:

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

19
Хоча це O (n * n).
Ганнес

@Hannes, чи не буде це O (n), оскільки він проходить цикл лише один раз і одночасно видаляє елемент?
пента

1
Розглянемо x = [1] * 10000 + [2] * 1000. Тіло циклу виконується 1000 разів і .remove () повинен пропускати 10000 елементів кожного разу, коли він викликається. Це пахне O (n * n) для мене, але не є доказом. Я думаю, що доказом може бути припущення, що кількість 2 у списку пропорційна його довжині. Цей коефіцієнт пропорційності потім зникає у позначенні big-O. Найкращий випадок лише постійної кількості 2s у списку - це не O (n ^ 2), а лише O (2n), який є O (n).
Ганнес

23

Дивіться просте рішення

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

Це поверне список із усіма елементами xбез2


11

Усі наведені вище відповіді (крім Мартина Андерссона) створюють новий список без потрібних елементів, а не вилучають їх із початкового списку.

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

Це може бути важливо, якщо у вас є інші посилання на список, який висить навколо.

Для зміни списку на місці використовуйте такий метод

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

Що стосується швидкості, результати на моєму ноутбуці є (усі в списку 5000 записів із 1000 видаленими записами)

  • Розуміння списку - ~ 400us
  • Фільтр - ~ 900us
  • .remove () петля - 50ms

Отже цикл .remove приблизно на 100 разів повільніше ........ Гммм, можливо, потрібен інший підхід. Найшвидший, який я знайшов, - це використання розуміння списку, але потім замінити вміст початкового списку.

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

Чому б тоді просто не перепризначити новий список під старою адресою? def remove_all(x, l): return [y for y in l if y != x]потімl = remove_all(3,l)
Даннід

@Dannid Це другий метод у першому кодовому полі. Він створює новий список, а ви не змінюєте старий список. Будь-які інші посилання на список залишатимуться нефільтрованими.
Пол S

Ага, правильно. Я так захопився у визначенні методу, що я не помітив просте завдання, яке ви вже зробили.
Даннід

7

ви можете це зробити

while 2 in x:   
    x.remove(2)

3
Це неправильне рішення, оскільки список потрібно пройти 2 * n разів для n випадків, що
відбулися

Не рекомендується додавати чи видаляти зі списку, який ви переглядаєте. Погана практика ІМХО.
Аман Матур

5

Ціною читабельності я вважаю, що ця версія трохи швидша, оскільки вона не змушує переглядати список, тим самим виконуючи таку саму роботу, як видалити.

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)

Для списку, який ви показуєте у своєму коді, цей підхід приблизно на 36% повільніше, ніж метод розуміння списку (який повертає копію), згідно з моїм вимірюванням.
djsmith

Добре, що ви це помітили. Однак, оскільки я думаю, що це, можливо, зірвало ваше судження, я порівнював свою версію з першою пропозицією, зробленою автором запитання.
Мартін Андерссон

4

Numpy підхід та таймінги для списку / масиву з 1.000.000 елементів:

Терміни:

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

Висновок: numpy в 27 разів швидше (на моєму зошиті) порівняно із підходом до розуміння списку

PS, якщо ви хочете перетворити ваш звичайний список Python lstу масив numpy:

arr = np.array(lst)

Налаштування:

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

Перевірка:

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)

Можливо, не самий пітонічний, але все-таки найлегший для мене ха-ха


3

Щоб видалити всі повторювані події та залишити їх у списку:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

Ось функція, яку я використав для Project Euler:

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

2
Мені потрібно було це зробити у векторі зі значеннями 250k, і це працює як шарм.
rschwieb

1
Відповідь: так! І я цілком розумію, якщо наявність вектора, який довго звучить грамотно для грамотного програміста. Я підходжу до проблем там як математик, не переживаючи за оптимізацію рішень, і це може призвести до рішень довше, ніж номінал. (Хоча я не маю терпіння для рішень довше 5 хвилин.)
rschwieb

6
Це видалить будь-яке замовлення зі списку.
asmeurer

4
@JaredBurrows, можливо, тому, що він відповідає не на питання, як зараз, а зовсім інше питання.
drevicko

6
-1, це не є відповіддю на питання ОП. Це рішення видалити дублікати, що зовсім інша справа.
Анойз

2

Я вважаю, що це, ймовірно, швидше, ніж будь-який інший спосіб, якщо ви не піклуєтесь про порядок списків, якщо ви подбаєте про остаточне замовлення, зберігайте індекси від оригіналу і вдайтеся до цього.

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

2
Я розумію, куди ви їдете, але цей код не працюватиме, оскільки вам знадобиться також індекс запуску, а не лише 0.
Шедокан

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

Набагато простіше я вірю.


2
будь ласка, відредагуйте свою відповідь, щоб покращити ясність. Будь ласка, уточніть, що саме робить ваш рекомендований код, чому він працює і чому це ваша рекомендація. Будь ласка, правильно відформатуйте своє запитання, щоб код був чітко помітний з решти вашої відповіді.
Ортунд

2

Дозволяє

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

Найпростішим та ефективним рішенням, як уже було розміщено раніше, є

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

Ще одна можливість, яка повинна використовувати менше пам'яті, але бути повільнішою, є

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

Результати часу для списків довжиною 1000 та 100000 з 10% відповідними записами: 0,16 проти 0,25 мс та 23 проти 123 мс.

Час із довжиною 1000

Час із довжиною 100000


1

Видаліть усі випадки значення зі списку 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()

Результат: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Крім того,

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)

Результат: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


"Python" вкладений для кожного if циклу "у функції, що працює зі 100% точністю!"
rafiqul786

Ви не змінюєте список, який ви просто друкуєте. Також називати список як списки є заплутаним
kon psych

0

Якщо у вас не було вбудованого filterабо не хочете використовувати додатковий простір, і вам потрібно лінійне рішення ...

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

['Привіт Світ']


будь ласка, спробуйте уточнити свою відповідь із поясненням.
парлада

0

Я щойно зробив це для списку. Я просто початківець. Трохи більш просунутий програміст, безумовно, може написати таку функцію.

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

0

Ми також можемо видалити на місці все, використовуючи delабо 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))

Тепер про ефективність:

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

Як ми бачимо, що додаткова версія remove_values_from_list()не потребує додаткової пам’яті, але для запуску потрібно набагато більше часу:

  • 11 секунд для встановлення значень видалення
  • 710 милли секунд для розуміння списку, що виділяє новий список в пам'яті

0

Ніхто не опублікував оптимальної відповіді за часовою та просторовою складністю, тому я подумав, що спробую це зробити. Ось рішення, яке видаляє всі події конкретного значення без створення нового масиву та з ефективної часовою складністю. Недолік - елементи не підтримують порядок .

Часова складність: O (n)
Додаткова складність простору: 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

Про швидкість!

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

Тільки з Python 3


2
Весело, це входить до сфери поставленого питання і є правильним.
Еріх

Я не бачу, як це правильно. Це видалить усі елементи зі списку, а не всі входження значення .
Георгій

-3

Що не так з:

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

Використання анаконди


2
Поясніть свої кодові рядки, щоб інші користувачі могли зрозуміти його функціональність. Дякую!
Ігнасіо Ара

Цей код нічого не видалить зі списку.
Георгій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.