【问题标题】:How to remove an element from a list by index如何按索引从列表中删除元素
【发布时间】:2010-10-12 06:18:46
【问题描述】:

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

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

【问题讨论】:

  • @smci:Python列表是基于数组的:要删除中间的一个项目,你必须移动右边的所有项目以消除间隙,这就是为什么它是O(n)的时间操作. deque() 在两端提供高效操作,但在中间不提供 O(1) 插入/查找/删除。
  • @J.F.Sebastian:cPython 实现,是的,感谢您的指正。严格来说,language spec 没有指定如何实现列表,替代实现可以选择使用链表。
  • @smci:没有实际的 Python 实现会使用O(n) 索引访问a[i](由于链表)。注意:基于数组的实现提供O(1) 索引访问。
  • @J.F.Sebastian:当然。我只是注意到语言规范没有定义这个,这是一个实现问题。 (我惊讶地发现它没有。)
  • @smci 如果您的目标范围很广,我不确定您希望如何优化任何内容。

标签: python list indexing


【解决方案1】:

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

Here 是教程中的部分。

【讨论】:

  • 谢谢,pop 和 del 有什么区别?
  • del 过载。例如 del a 删除整个列表
  • 另一个例子 del a[2:4],删除元素 2 和 3
  • pop() 返回要删除的元素。 del 只是删除 is。
  • 我在那里看不到“链表”的证明。看看svn.python.org/projects/python/trunk/Objects/listobject.c PyList_GetItem() 本质上是如何返回((PyListObject *)op) -> ob_item[i]; - 数组的ith 元素。
【解决方案2】:

你可能想要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']

【讨论】:

  • 顺便说一句,pop() 返回它删除的任何元素。
  • @S.Lott:它默认使用结尾,因为那里是 O(1);一开始是 O(n)。
  • 这个答案不正确。 pop() 返回从数组中删除的值,而不是没有您想要删除的值的数组,如代码的 cmets 所示。我相信它没有回答最初的问题,因为它没有被问到如何从数组中提取值而是删除它。
  • @Seb,您是正确的,因为它返回了您删除的值,但问题中没有要求必须重新生成或返回列表。由于pop 改变了列表,它完全满足了问题提出的要求,尽管返回值是多余的。我什至认为 pop 比公认的答案更正确,因为 del 是一个与正在运行的程序的内存管理密切相关的关键字,而 list.pop 是蟒蛇。
  • 总之,我是使用del 还是pop 来修改和删除该元素而不会出现奇怪的错误?
【解决方案3】:

与其他人提到的一样,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]

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

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

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

ThisStack 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 )

这适用于定义__getitem____add__ 方法的list

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

假设以下是预定义的:

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

注意:在所有三个反汇编中,忽略最后两行基本上是return None。此外,前两行正在加载全局值 aindex

【讨论】:

  • 您的切片方法不会从列表中删除元素:而是创建一个 new 列表对象,其中包含原始列表中除第 i 个条目之外的所有条目。原始列表保持不变。
  • @MarkDickinson 已经编辑了答案以澄清同样的问题......如果现在看起来不错,请告诉我?
  • 也许答案并不完全在主题上,但是如果您需要从不可变对象(例如元组)中省略项目,索引方法很有用。 pop() 和 del() 在这种情况下将不起作用。
  • @rvraghav93 在整个帖子中提出的所有方法中,a = a[:index] + a[index+1 :]-trick 是最节省的,当涉及到大量列表时。所有其他方法最终陷入僵局。所以非常感谢你
  • 确实马克,你脾气暴躁。这个答案是我更喜欢的答案,因为它真的很有教学意义。我从这个答案和提供的反汇编细节以及对性能的影响中学到了最多。加上切片方法,是的,创建另一个对象,但现在它是指定的,有时这也是你需要的。
【解决方案4】:

pop 对于从列表中删除和保留项目也很有用。 del 实际上是在哪里丢弃了该项目。

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

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

【讨论】:

    【解决方案5】:

    如果要删除列表中特定位置的元素,例如第 2、3 和第 7 个元素,则不能使用

    del my_list[2]
    del my_list[3]
    del my_list[7]
    

    既然你删除了第二个元素,那么你删除的第三个元素实际上就是原始列表中的第四个元素。您可以过滤原始列表中的第 2、第 3 和第 7 个元素并得到一个新列表,如下所示:

    new_list = [j for i, j in enumerate(my_list) if i not in [2, 3, 7]]
    

    【讨论】:

    • 适合我的需要。我需要浏览一个列表并删除其中的一些。因此,使用这种方法,我只需将要删除的元素的索引保存在另一个列表中,然后最后我将使用您提供的方法一次将它们全部删除。
    • 你仍然可以重复调用del,只要你从最大的索引开始,就像在nspo的回答中一样。
    【解决方案6】:

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

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

    【讨论】:

      【解决方案7】:

      这取决于你想做什么。

      如果要返回删除的元素,请使用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:])。

      【讨论】:

        【解决方案8】:

        使用del 语句:

        del listName[-N]
        

        例如,如果你想删除最后 3 项,你的代码应该是:

        del listName[-3:]
        

        例如,如果你想删除最后 8 项,你的代码应该是:

        del listName[-8:]
        

        【讨论】:

          【解决方案9】:

          一般情况下,我使用以下方法:

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

          【讨论】:

            【解决方案10】:

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

            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] 指向从索引xy-1 的元素。当我们将列表的该部分声明为空列表 ([]) 时,这些元素将被删除。

            【讨论】:

              【解决方案11】:

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

                  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

              【讨论】:

              • 我喜欢这个解决方案,但它当然假设您的列表没有重复项。
              【解决方案12】:

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

              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]
              

              【讨论】:

              • 附带一个警告,您的列表不能包含重复项。
              • 这不是按索引删除,而是按匹配值删除。对于一些访问这里的人来说,这可能是有价值的信息,但根本不会尝试回答 OP 的问题。
              【解决方案13】:

              如前所述,最佳实践是 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() / 列表理解来做到这一点。

              思考

              【讨论】:

              • 哪个版本的Python有函数del()?对于该函数,您提供列表作为该函数的第一个参数,然后是索引,还是先提供索引,然后是列表?它是返回不带项目的列表参数,还是原地删除。我知道del 语句,但不知道同名函数。
              【解决方案14】:

              l - 值列表;我们必须从 inds2rem 列表中删除索引。

              l = range(20)
              inds2rem = [2,5,1,7]
              map(lambda x: l.pop(x), sorted(inds2rem, key = lambda x:-x))
              
              >>> l
              [0, 3, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
              

              【讨论】:

              • 不工作,答案是&lt;map at 0x7f4d54109a58&gt;。和 l 是范围(0,20)
              【解决方案15】:

              听起来您不是在处理列表列表,所以我会保持简短。你想使用 pop 因为它会删除元素而不是列表元素,你应该使用 del 。要调用python中的最后一个元素,它是“-1”

              >>> test = ['item1', 'item2']
              >>> test.pop(-1)
              'item2'
              >>> test
              ['item1']
              

              【讨论】:

              • pop()del 都在提供的索引处删除一个元素,与该元素本身是否是列表无关。 a = [1, [2, 3], 4]; del a[1]; b = [1, [2, 3], 4]; b.pop(1); assert a == b
              【解决方案16】:

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

              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])
              

              【讨论】:

              • 为什么不把索引列表倒序排列,然后一一删除呢?这样您就不必制作新列表了。
              【解决方案17】:

              您可以使用 del 或 pop 根据索引从列表中删除元素。 Pop 将打印它正在从列表中删除的成员,而列表删除该成员而不打印它。

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

              【讨论】:

                【解决方案18】:

                可以使用 del 或 pop,但我更喜欢 del,因为您可以指定索引和切片,从而使用户可以更好地控制数据。

                例如,从显示的列表开始,可以使用del 作为切片删除其最后一个元素,然后可以使用pop 从结果中删除最后一个元素。

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

                【讨论】:

                  猜你喜欢
                  • 2020-01-02
                  • 1970-01-01
                  • 2017-12-16
                  • 1970-01-01
                  • 2010-10-26
                  • 2016-12-03
                  相关资源
                  最近更新 更多