如何从列表中删除所有不符合要求的元素

时间:2015-09-03 07:45:56

标签: python list

我有一个清单:

my_list = ['a', 'b', 'c', 'a', 'b', 'c', 'a']

我使用以下代码删除不符合要求的元素:

[my_list.remove(element) for element in my_list if 'a' not in element]

但不是预期['a', 'a', 'a']获得['a', 'c', 'a', 'c', 'a']。似乎在删除'b' Python后没有检查'c'个元素......

请告诉我如何解决此问题并有效地从列表中删除所有不必要的元素。

5 个答案:

答案 0 :(得分:8)

其他答案解决了这个问题,但让我解释一下这里发生了什么。

>>> lst = ['a', 'b', 'c', 'a', 'b', 'c', 'a']
>>> for each in lst:
...     if 'a' not in each:
...         lst.remove(each)
>>> lst
['a', 'c', 'a', 'c', 'a']

迭代1:

#   V                                     - Current position of loop
# ['a', 'b', 'c', 'a', 'b', 'c', 'a']

if 'a' not in each: #Output False

迭代2:

#        V                                - Current position of loop
# ['a', 'b', 'c', 'a', 'b', 'c', 'a']

if 'a' not in each: #Output True
    list.remove(each)  #Element from position 1 ('b') in list is removed

迭代3:

#             V                         |___ Supposed to be like this  
# ['a', 'b', 'c', 'a', 'b', 'c', 'a']   |

#             V                         |___ Updated list
# ['a', 'c', 'a', 'b', 'c', 'a']        |

if 'a' not in each: #Output False

这就是为什么你的' c'在输出列表中跳过。

现在要解决您的问题,而不是删除所有非a,这是创建仅包含a的列表的更好方法。 (Trengot's Answer

编辑:

由于您的my_list是字符集合,因此最好使用if 'a' != element,因为'a' not in element将扫描元素的每个字母,并且还会删除所有带字母的元素'a'Check this to understand how in works in Python)。

例如,如果您的my_list = ['a','abc','fd','b','c']'a' not in 'abc'将返回False,则元素'abc'将无法删除。

答案 1 :(得分:3)

将列表过滤为新列表,选择您想要的元素,而不是删除不需要的元素。然后使用新的或将其分配给旧的。

my_list = [element for element in my_list if 'a' in element]

正如Peter Wood指出的那样,这将为my_list分配一个新对象。如果您想保留相同的列表对象(例如,如果它也在其他地方引用),请将新列表分配给my_list[:]

my_list[:] = [element for element in my_list if 'a' in element]

答案 2 :(得分:1)

由于您想要就地修改(缩小)现有列表,所以这里有以下内容:

def remove_all_on_predicate(predicate, list_):
    deserving_removal = [elem for elem in list_ if predicate(elem)]
    for elem in deserving_removal:
        list_.remove(elem)
    return None

>>> remove_all_on_predicate(lambda x: "a" not in x, my_list)
>>> my_list
['a', 'a', 'a']

答案 3 :(得分:1)

正如您所发现的那样,尝试从正在迭代的列表中删除元素可能无法达到预期效果。 Ashwani Agarwal的回答说明了它失败的原因,其他答案显示了可用于正确执行删除的各种技术。当你有一个你无法复制的非常大的列表时,另一种有用的技术就是反过来迭代它:

my_list = ['a', 'b', 'c', 'a', 'b', 'c', 'a']
for element in reversed(my_list):
    if 'a' not in element:
        my_list.remove(element)
        print(element, my_list)

print('Final:', my_list)

my_list = ['a', 'b', 'c', 'a', 'b', 'c', 'a']
for element in reversed(my_list):
    if 'a' in element:
        my_list.remove(element)
        print(my_list)

print('Final:', my_list)

<强>输出

c ['a', 'b', 'a', 'b', 'c', 'a']                                                                                                               
c ['a', 'b', 'a', 'b', 'a']                                                                                                                    
b ['a', 'a', 'b', 'a']                                                                                                                         
b ['a', 'a', 'a']                                                                                                                              
Final: ['a', 'a', 'a']                                                                                                                         
['b', 'c', 'a', 'b', 'c', 'a']                                                                                                                 
['b', 'c', 'b', 'c', 'a']
['b', 'c', 'b', 'c']
Final: ['b', 'c', 'b', 'c']

此代码使用reversed()函数,该函数返回传递给它的迭代器上的迭代器;它不会复制可迭代的。

我应该提一下,这种技术的效率低于其他答案中给出的过滤方法。这是因为my_list.remove(element)的每次调用都必须扫描my_list,直到找到匹配的元素,因此它具有复杂度O(n ** 2),其中n是数字列表中的元素;滤波算法具有O(n)的复杂度。正如我之前所说,这种方法仅在列表太大以至于无法提供RAM来创建新列表时才有用。

我还需要提一下你的问题中的代码:当你应该使用普通的for循环时,你正在使用列表推导来遍历列表。 list.remove()会返回None,因此您的代码会不必要地创建一个充满None s的列表,然后将该列表丢弃。一般规则是:不要仅仅使用列表理解来调用你在其中调用的函数的副作用。

答案 4 :(得分:0)

我使用filter

my_list = filter(lambda x: 'a' in x, my_list)