从列表中删除多个元素

206

有没有可能同时从列表中删除多个元素?如果我想删除索引为0和2的元素,并尝试类似于del somelist [0]然后跟着del somelist [2],第二条语句实际上会删除somelist[3]

我猜我可以总是先删除较高编号的元素,但我希望有更好的方法。


如果你关心效率,可以使用多个切片。 - tejasvi88
32个回答

4

这里还有另一种方法可以原地删除元素。而且如果你的列表非常长,使用这种方法更快。

>>> a = range(10)
>>> remove = [0,4,5]
>>> from collections import deque
>>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)

>>> timeit.timeit('[i for j, i in enumerate(a) if j not in remove]', setup='import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.1704120635986328

>>> timeit.timeit('deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)', setup='from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.004853963851928711

+1:有趣的deque使用,作为表达式的一部分执行for操作,而不需要“for ..:”块。然而,对于这种简单情况,我发现Nikhil的for块更易读。 - ToolmakerSteve

4
l = ['a','b','a','c','a','d']
to_remove = [1, 3]
[l[i] for i in range(0, len(l)) if i not in to_remove])

实际上这与得票最高的答案基本相同,只是写法不同。请注意,使用 l.index() 不是个好主意,因为它无法处理列表中的重复元素。


4

虽然这个问题已经被提到过,但似乎没有人成功将其解决。

一个 O(n) 的解决方案是:

indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]

这与SilentGhost版本非常接近,但添加了两个花括号。


如果每次迭代都要进行需要 log(len(indices)) 的查找操作,那么这就不是 O(n) - Mad Physicist
@MadPhysicist j not in indicesO(1) - Veedrac
我不确定你是如何得到那个数字的。由于indices是一个集合,j not in indices仍需要查找,这是O(log(len(indices)))。虽然我同意在2元素集合中的查找符合O(1),但在一般情况下它将是O(log(N))。无论哪种方式,O(N log(N))仍然优于O(N^2) - Mad Physicist
3
"j not in indices是O(1)的,说真的。" - Veedrac
两个大括号到底是做什么的? - Nuclear03020704
@Nuclear03020704 https://docs.python.org/3.3/tutorial/datastructures.html#sets - Veedrac

2

总结来自@sth的评论。任何实现了abc.MutableSequence接口的类,特别是list,都可以通过__delitem__魔术方法删除项目。该方法与__getitem__类似,意味着它可以接受整数或切片。以下是一个例子:

class MyList(list):
    def __delitem__(self, item):
        if isinstance(item, slice):
            for i in range(*item.indices(len(self))):
                self[i] = 'null'
        else:
            self[item] = 'null'


l = MyList(range(10))
print(l)
del l[5:8]
print(l)

这将输出。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 'null', 'null', 'null', 8, 9]

2

从技术角度来说,不能同时删除两个对象。但是,通过一行简洁优美的Python代码,可以同时删除两个对象。

del (foo['bar'],foo['baz'])

将递归删除foo['bar'],然后删除foo['baz']


这会从字典对象中删除,而不是列表,但我仍然+1因为它非常漂亮! - Ulf Aslak
它同样适用于列表,具有适当的语法。然而,声称不可能同时删除两个对象是错误的;请参见@bobince的答案。 - Pedro Gimeno

2

另一种实现从最高索引处删除的方法。

for i in range(len(yourlist)-1, -1, -1):
    del yourlist(i)

2
您可以使用以下逻辑:
my_list = ['word','yes','no','nice']

c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]

print c

2
我们可以通过使用一个for循环来迭代排序后的索引列表中的索引,以此来实现。
mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65]
indexes = 4,6
indexes = sorted(indexes, reverse=True)
for i in index:
    mylist.pop(i)
print mylist

2

对于列表A中的索引0和2:

for x in (2,0): listA.pop(x)

需要从listA中随机删除一些索引:

indices=(5,3,2,7,0) 
for x in sorted(indices)[::-1]: listA.pop(x)

2

remove方法会导致列表元素大量移动,我认为最好制作一个副本:

...
new_list = []
for el in obj.my_list:
   if condition_is_true(el):
      new_list.append(el)
del obj.my_list
obj.my_list = new_list
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接