2013-07-02 2 views
0

У меня есть два списка, показанных ниже. Я пытаюсь использовать функцию list.remove (x), чтобы удалить файлы, которые находятся в обоих списках1 и list2, но в одном из моих списков есть расширения файлов, а другое нет! Какой должен быть мой подход !?Python list.remove (x) 2.7.5

List1 = ['myfile.v', 'myfile2.sv', 'myfile3.vhd', 'etcfile.v', 'randfile.sv'] 
List2 = ['myfile', 'myfile2', 'myfile3'] 

#This is in short what I would like to do, but the file extensions throw off 
#the tool! 
for x in List2: 
    List1.remove(x) 

Спасибо!

ответ

8

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

>>> L = [1, 1, 2, 2, 3, 3] 
>>> for x in L: 
...     print x 
...     if x == 2: 
...   L.remove(2) 
...  
1 
1 
2 
3 
3 

Это неэффективно, поскольку каждый .remove О (п) сложность

Лучше создать новый список и связать его обратно list1

import os 
list1 = ['myfile.v', 'myfile2.sv', 'myfile3.vhd', 'etcfile.v', 'randfile.sv'] 
list2 = ['myfile', 'myfile2', 'myfile3'] 
set2 = set(list2) # Use a set for O(1) lookups 
list1 = [x for x in list1 if os.path.splitext(x)[0] not in set2] 

или для «INPLACE» версии

list1[:] = [x for x in list1 if os.path.splitext(x)[0] not in set2] 

для подлинной версии inplace, как описано в комментарии - не использует дополнительную O (n) память. И работает в O (п)

>>> list1 = ['myfile.v', 'myfile2.sv', 'myfile3.vhd', 'etcfile.v', 'randfile.sv'] 
>>> p = 0 
>>> for x in list1: 
...  if os.path.splitext(x)[0] not in set2: 
...   list1[p] = x 
...   p += 1 
... 
>>> del(list1[p:]) 
>>> list1 
['etcfile.v', 'randfile.sv'] 
+0

Последний на самом деле не «на месте» - он все еще создает копию и затем мутирует исходный список, чтобы он соответствовал копии. Вероятно, нет никакой веской причины действительно хотеть здесь мутации на месте, но если вы этого хотите, вы должны фактически использовать 'remove' /' del'/'pop'/etc. (Это отличный ответ любым другим способом, особенно объяснение того, почему OP должен просто создать новый список.) – abarnert

+0

@abarnert, это «на месте», поскольку могут быть другие ссылки на список1, которые вы ожидаете чтобы увидеть удаления –

+1

Да, это именно то, что я имел в виду под «создает копию, а затем мутирует исходный список для соответствия копии». Мутирование исходного списка в соответствии с копией - это то, почему другие ссылки будут видеть удаления. Но он по-прежнему не является алгоритмом на месте, это алгоритм копирования. – abarnert

0

Ради этого, если вы хотите использовать list.remove(element), так как это очень легко читать для других, вы можете попробовать следующее. Если у вас есть функция F, которая возвращает истину, если значение правильно/проходит определенные испытания в соответствии с требованиями,

Так как это не будет работать:

def rem_vals(L): 
    for x in L: 
     if not f(x): 
      L.remove(x) 

более одного значения, которое будет удалено в списке L , мы можем использовать рекурсию следующим образом:

def rem_vals_rec(L): 
    for x in L: 
     if not f(x): 
      L.remove(x) 
      rem_vals_rec(L) 

Не самый быстрый, но самый легкий для чтения.