题 如何在Python中通过索引从列表中删除元素?


如何在Python中通过索引从列表中删除元素?

我找到了 list.remove 方法,但是说我要删除最后一个元素,我该怎么做?似乎默认删除搜索列表,但我不希望执行任何搜索。


1054
2018-03-09 18:16


起源


可扩展的答案是使用 collections.deque - smci
@smci:中间的删除是O(n)无论是列表还是双端队列。 - jfs
是的,@ j-f-sebastian,你说的没错。后来我发现deque只能提高插入的可扩展性;不查找(O(1))或删除。我删除了错误的答案。但是我认为(列表)删除索引只是一个查找后跟一个删除(和内部内存重新分配),所以他们肯定是O(1)而不是O(n)?按值删除确实是O(n),因为它们涉及遍历。 - smci
@smci:Python列表是基于数组的:要删除中间的项目,你必须移动右边的所有项目以消除差异,这就是为什么它是 O(n) 及时操作。 deque() 在两端提供有效的操作,但它不在中间提供O(1)插入/查找/删除。 - jfs
@ J.F.Sebastian:cPython实施,是的,谢谢你纠正我。严格来说 语言规范 没有指定如何实现列表,替代实现可以选择使用链表。 - smci


答案:


使用 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]

这里 是本教程的一部分。


1216
2018-03-09 18:21



谢谢,pop和del有什么区别? - Joan Venge
del超载。例如,del a删除整个列表 - Brian R. Bondy
另一个例子del a [2:4],删除元素2和3 - Brian R. Bondy
pop()返回要删除的元素。 del just删除是。
我在那里看不到“链表”的证明。看着 svn.python.org/projects/python/trunk/Objects/listobject.c 怎么样 PyList_GetItem() 基本上回报 ((PyListObject *)op) -> ob_item[i];  - i数组的元素。 - glglgl


你可能想要 pop

a = ['a', 'b', 'c', 'd']
a.pop(1)

# now a is ['a', 'c', 'd']

默认, pop 没有任何参数删除最后一项:

a = ['a', 'b', 'c', 'd']
a.pop()

# now a is ['a', 'b', 'c']

490
2018-03-09 18:17



不要忘记pop(-1)。是的,这是默认设置,但我更喜欢它,所以我不必记住默认情况下哪个结束弹出使用。 - S.Lott
好点......这确实提高了可读性。 - Jarret Hardie
我不同意。如果你知道程序员的“pop”的词源(它是删除并返回的操作) 最佳 然后,'堆栈'数据结构) pop() 本身非常明显,而 pop(-1) 可能会让人感到困惑 因为 这是多余的。 - CoreDumpError
@ zx1986 a pop 在大多数编程语言中,通常会删除最后一项,就像在Python中一样。所以无论你指定-1还是什么都没有。 - Pascal
顺便一提, pop() 返回它删除的任何元素。 - Bob Stein


像其他提到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:]))并通过添加两者来创建新的列表对象。然后将其重新分配给list变量(a)。因此,旧的列表对象被解除引用并因此被垃圾收集(假设原始列表对象不被除了a之外的任何变量引用)。

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

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

这个 Stack Overflow回答解释了切片的概念。

另请注意,这仅适用于正指数。

在使用对象时, __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 )

这适用于 list 它定义了 __getitem__ 和 __add__ 方法。

在效率方面比较三种方式:

假设以下是预定义的:

a = range(10)
index = 3

del object[index] 方法:

到目前为止最有效的方法。它适用于定义a的所有对象 __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

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


96
2018-06-22 15:21



切片方法不会从列表中删除元素:而是创建一个元素 新 列表对象,包含原始列表中除第i个条目以外的所有条目。原始列表未经修改。 - Mark Dickinson
@MarkDickinson编辑了答案以澄清相同的内容...如果现在看起来不错,请告诉我? - Raghav RV
也许答案并非完全基于主题,但如果您需要省略不可变对象(例如元组)中的项,则索引方法很有用。 pop()和del()在这种情况下不起作用。 - Caleb
@ rvraghav93在整个帖子中提出了所有方法 a = a[:index] + a[index+1 :]当谈到庞大的名单时,-trick是最令人讨厌的。所有其他方法最终陷入僵局。非常感谢你 - user3085931
事实上马克,你脾气暴躁。这个答案是我最喜欢的,因为它真的是教学法。我从这个答案和所提供的拆卸细节以及对性能的影响中学到了很多东西。再加上切片方法,是的,创建另一个对象,但现在它被指定,有时这也是你需要的。 - Yohan Obadia


pop 从列表中删除和保留项目也很有用。哪里 del实际上是破坏了这个项目。

>>> x = [1, 2, 3, 4]

>>> p = x.pop(1)
>>> p
    2

42
2017-10-19 13:10



因为4年前的答案没有提及 pop 返回删除的值。它只是显示它从列表中删除值。相反 del 实际上删除它而不给你一份副本。这些评论都没有提到它。 - boatcoder


一般来说,我使用以下方法:

>>> myList = [10,20,30,40,50]
>>> rmovIndxNo = 3
>>> del myList[rmovIndxNo]
>>> myList
[10, 20, 30, 50]

12
2017-10-05 12:23





这取决于你想做什么。

如果要返回删除的元素,请使用 pop()

>>> l = [1, 2, 3, 4, 5]
>>> l.pop(2)
3
>>> l
[1, 2, 4, 5]

但是,如果您只想删除元素,请使用 del

>>> l = [1, 2, 3, 4, 5]
>>> del l[2]
>>> l
[1, 2, 4, 5]

另外, del 允许你使用切片(例如 del[2:])。


10
2017-08-11 00:17





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

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。当我们将列表的那部分声明为空列表时([]),删除那些元素。


6
2017-10-30 09:21



我喜欢这个,谢谢! - jacktrader


您只需搜索要删除的项目即可。这很简单。 例:

    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


6
2018-02-15 13:09



您定义的变量名称是 letters,但是你将其称为 numbers - Todor


使用以下代码从列表中删除元素:

list = [1, 2, 3, 4]
list.remove(1)
print(list)

output = [2, 3, 4]

如果要从列表中删除索引元素数据,请使用:

list = [1, 2, 3, 4]
list.remove(list[2])
print(list)
output : [1, 2, 4]

5
2018-05-14 13:29





如前所述,最佳实践是del();或pop()如果你需要知道值。

另一种解决方案是仅重新堆叠所需的元素:

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

    def remove_element(list_,index_):
        clipboard = []
        for i in range(len(list_)):
            if i is not index_:
                clipboard.append(list_[i])
        return clipboard

    print(remove_element(a,2))

    >> ['a', 'b', 'd']

eta:嗯...不会对负指数值起作用,会进行思考和更新

我想

if index_<0:index_=len(list_)+index_

会修补它...但突然间这个想法似乎非常脆弱。虽然有趣的思想实验。似乎应该有一个“正确”的方法来执行append()/ list comprehension。

琢磨


3
2018-06-28 03:15