如何按索引从列表中删除元素?

我找到了list.remove(),但这会缓慢地按值扫描列表中的项。


当前回答

使用del并指定要删除的元素的索引:

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del a[-1]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8]

还支持切片:

>>> del a[2:4]
>>> a
[0, 1, 4, 5, 6, 7, 8, 9]

这是教程中的部分。

其他回答

您可以只搜索要删除的项目。这真的很简单。例子:

    letters = ["a", "b", "c", "d", "e"]
    letters.remove(letters[1])
    print(*letters) # Used with a * to make it unpack you don't have to (Python 3.x or newer)

输出:a c d e

像其他提到的pop和del是删除给定索引项的有效方法。然而,仅仅为了完成(因为在Python中可以通过多种方式完成相同的任务):

使用切片(这不会从原始列表中就地删除项目):

(在使用Python列表时,这也是效率最低的方法,但在使用不支持pop但定义了__getitem__的用户定义对象时,这可能很有用(但我重申这不是有效的):

>>> a = [1, 2, 3, 4, 5, 6]
>>> index = 3 # Only positive index

>>> a = a[:index] + a[index+1 :]
# a is now [1, 2, 3, 5, 6]

注意:请注意,此方法不会像pop和del那样就地修改列表。它会创建两个列表副本(一个从开始到索引,但没有索引(a[:index]),一个在索引之后,直到最后一个元素(a[index+1:])),并通过添加这两个副本创建一个新的列表对象。然后将其重新分配给列表变量(a)。因此,旧列表对象被取消引用,因此被垃圾收集(前提是原始列表对象未被除a之外的任何变量引用)。

这使得该方法非常低效,并且还会产生不希望的副作用(特别是当其他变量指向未修改的原始列表对象时)。

感谢@MarkDickinson指出这一点。。。

堆栈溢出的答案解释了切片的概念。

还要注意,这只适用于正指数。

在与对象一起使用时,__getitem__方法必须已定义,更重要的是__add__方法必须定义为返回包含两个操作数中的项的对象。

本质上,这适用于类定义如下的任何对象:

class foo(object):
    def __init__(self, items):
        self.items = items

    def __getitem__(self, index):
        return foo(self.items[index])

    def __add__(self, right):
        return foo( self.items + right.items )

这适用于定义__getitem__和__add__方法的列表。

三种方式的效率比较:

假设以下是预定义的:

a = range(10)
index = 3

del object[index]方法:

迄今为止最有效的方法。它适用于定义__del__方法的所有对象。

拆卸如下:

代码:

def del_method():
    global a
    global index
    del a[index]

拆卸:

 10    0 LOAD_GLOBAL     0 (a)
       3 LOAD_GLOBAL     1 (index)
       6 DELETE_SUBSCR   # This is the line that deletes the item
       7 LOAD_CONST      0 (None)
      10 RETURN_VALUE
None

pop方法:

它比del方法效率低,并且在需要获取已删除项时使用。

代码:

def pop_method():
    global a
    global index
    a.pop(index)

拆卸:

 17     0 LOAD_GLOBAL     0 (a)
        3 LOAD_ATTR       1 (pop)
        6 LOAD_GLOBAL     2 (index)
        9 CALL_FUNCTION   1
       12 POP_TOP
       13 LOAD_CONST      0 (None)
       16 RETURN_VALUE

切片和添加方法。

效率最低。

代码:

def slice_method():
    global a
    global index
    a = a[:index] + a[index+1:]

拆卸:

 24     0 LOAD_GLOBAL    0 (a)
        3 LOAD_GLOBAL    1 (index)
        6 SLICE+2
        7 LOAD_GLOBAL    0 (a)
       10 LOAD_GLOBAL    1 (index)
       13 LOAD_CONST     1 (1)
       16 BINARY_ADD
       17 SLICE+1
       18 BINARY_ADD
       19 STORE_GLOBAL   0 (a)
       22 LOAD_CONST     0 (None)
       25 RETURN_VALUE
None

注意:在所有三个反汇编中,忽略最后两行,这两行基本上是返回None。前两行还加载全局值a和index。

或者如果应删除多个索引:

print([v for i,v in enumerate(your_list) if i not in list_of_unwanted_indexes])

当然,也可以这样做:

print([v for i,v in enumerate(your_list) if i != unwanted_index])

已经提到了如何从列表中删除单个元素,以及不同的方法有哪些优点。但是,请注意,删除多个元素可能会出错:

>>> l = [0,1,2,3,4,5,6,7,8,9]
>>> indices=[3,7]
>>> for i in indices:
...     del l[i]
... 
>>> l
[0, 1, 2, 4, 5, 6, 7, 9]

原始列表的元素3和8(而不是3和7)已被删除(因为列表在循环过程中被缩短),这可能不是本意。如果您希望安全地删除多个索引,则应首先删除索引最高的元素,例如:

>>> l = [0,1,2,3,4,5,6,7,8,9]
>>> indices=[3,7]
>>> for i in sorted(indices, reverse=True):
...     del l[i]
... 
>>> l
[0, 1, 2, 4, 5, 6, 8, 9]

另一种通过索引从列表中删除元素的方法。

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# remove the element at index 3
a[3:4] = []
# a is now [0, 1, 2, 4, 5, 6, 7, 8, 9]

# remove the elements from index 3 to index 6
a[3:7] = []
# a is now [0, 1, 2, 7, 8, 9]

a[x:y]指向从索引x到y-1的元素。当我们将列表的该部分声明为空列表([])时,这些元素将被删除。