Изящный способ удалить объекты из последовательности в Python? [дубликат]

Проверьте синтаксис URI пакета . Вы хотите что-то вроде этого:


55
задан Andy Lester 2 October 2008 в 17:33
поделиться

11 ответов

Два простых способа выполнить просто фильтрацию:

  1. Используя filter:

    names = filter(lambda name: name[-5:] != "Smith", names)

  2. Используя понимания списка:

    names = [name for name in names if name[-5:] != "Smith"]

Примечание, что оба случая сохраняют значения, для которых функция предиката оценивает к True, таким образом, необходимо инвертировать логику (т.е. Вы говорите, "сохраняют людей, у которых нет фамилии, Smith" вместо "удаляет людей, у которых есть фамилия Smith").

Редактирование Забавный... два человека индивидуально отправили оба из ответов, которые я предложил, поскольку я отправлял мой.

56
ответ дан Ray Vega 7 November 2019 в 17:05
поделиться

Ну, это - ясно проблема со структурой данных, которую Вы используете. Используйте хеш-таблицу, например. Некоторые реализации поддерживают многократные въезды на ключ, таким образом, можно или вытолкать новейший элемент прочь, или удалять всех их.

, Но это, и что Вы собираетесь найти, что решение, элегантность через различную структуру данных, не алгоритм. Возможно, можно добиться большего успеха, если это отсортировано, или что-то, но повторение в списке является единственным методом здесь.

редактирование: каждый действительно понимает, что попросил 'эффективность'..., все эти предложенные методы просто выполняют итерации по списку, который совпадает с тем, что он предложил.

-2
ответ дан nlucaroni 7 November 2019 в 17:05
поделиться

Фильтр и понимания списка хорошо для Вашего примера, но у них есть несколько проблем:

  • Они делают копию Вашего списка и возвращают новый, и это будет неэффективно, когда исходный список будет действительно большой
  • , Они могут быть действительно громоздкими когда критерии для выбора объектов (в случае, если имя [-5:] == 'Smith'), более сложно, или имеет несколько условий.

Ваше исходное решение на самом деле более эффективно для очень больших списков, даже если мы можем согласиться, что это более ужасно. Но если Вы волнуетесь, что у Вас могут быть несколько 'John Smith', это может быть зафиксировано путем удаления на основе положения а не на значении:

names = ['Jones', 'Vai', 'Smith', 'Perez', 'Smith']

toremove = []
for pos, name in enumerate(names):
    if name[-5:] == 'Smith':
        toremove.append(pos)
for pos in sorted(toremove, reverse=True):
    del(names[pos])

print names

Мы не можем выбрать решение, не рассматривая размера списка, но для больших списков я предпочел бы Ваше решение с 2 передачами вместо фильтра или перечисляю понимания

1
ответ дан Ricardo Reyes 7 November 2019 в 17:05
поделиться

Для ответа на вопрос о работе со словарями необходимо отметить, что Python 3.0 будет включать dict понимания :

>>> {i : chr(65+i) for i in range(4)}

Тем временем, можно сделать quasi-dict понимание этот путь:

>>> dict([(i, chr(65+i)) for i in range(4)])

Или как более прямой ответ:

dict([(key, name) for key, name in some_dictionary.iteritems if name[-5:] != 'Smith'])
2
ответ дан Jason Baker 7 November 2019 в 17:05
поделиться

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

for name in names[:]:
    if name[-5:] == 'Smith':
        names.remove(name)

единственной разницей от исходного кода является использование names[:] вместо names в для цикла. Тем путем код выполняет итерации по (мелкой) копии списка и работы удалений как ожидалось. Так как список, копирующий, мелок, это довольно быстро.

4
ответ дан elifiner 7 November 2019 в 17:05
поделиться

Используя понимание списка

list = [x for x in list if x[-5:] != "smith"]
10
ответ дан Corey 7 November 2019 в 17:05
поделиться

фильтр был бы потрясающим для этого. Простой пример:

names = ['mike', 'dave', 'jim']
filter(lambda x: x != 'mike', names)
['dave', 'jim']

Редактирование: понимание списка Corey является потрясающим также.

3
ответ дан mk. 7 November 2019 в 17:05
поделиться

Можно также выполнить итерации назад по списку:

for name in reversed(names):
    if name[-5:] == 'Smith':
        names.remove(name)

Это имеет преимущество, что оно не создает новый список (как filter или понимание списка) и использует итератор вместо копии списка (как [:]).

Примечание, которое, хотя удаляя элементы при итерации назад безопасно, вставляя их, несколько более хитро.

37
ответ дан Xavier Martinez-Hidalgo 7 November 2019 в 17:05
поделиться
names = filter(lambda x: x[-5:] != "Smith", names);
2
ответ дан pottedmeat 7 November 2019 в 17:05
поделиться

Оба решения, фильтр и понимание требуют создания нового списка. Я не знаю, что достаточно внутренностей Python уверено, но я думаю , что более традиционное (но менее изящный) подход могло быть более эффективным:

names = ['Jones', 'Vai', 'Smith', 'Perez']

item = 0
while item <> len(names):
    name = names [item]
    if name=='Smith':
        names.remove(name)
    else:
        item += 1

print names

Так или иначе, для коротких списков, я придерживаюсь любого из этих двух решений, предложенных ранее.

2
ответ дан PabloG 7 November 2019 в 17:05
поделиться

В случае набора.

toRemove = set([])  
for item in mySet:  
    if item is unwelcome:  
        toRemove.add(item)  
mySets = mySet - toRemove 
1
ответ дан 26 November 2019 в 17:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: