【问题标题】:Slicing List Confusion in PythonPython中的切片列表混淆
【发布时间】:2012-12-13 18:15:25
【问题描述】:

好吧,我是 Python 的超级新手,但对于切片列表,有些事情困扰着我。当我从这段代码中切片 [1] 和 [3] 时,为什么会得到 [1, 3, 4]?

z = [1, 2, 3, 4, 5]
del z[1], z[3]
print z

我以为我会得到 [1, 3, 5] 回来,因为它似乎 [2] 和 [4] 正在被删除。

如果-->[1, 2, 3, 4, 5]
是-->[0, 1, 2, 3, 4]

我的逻辑哪里搞错了?

【问题讨论】:

    标签: python list slice del


    【解决方案1】:

    第一次删除改变了列表索引,所以下一个不是之前的位置...... 简化

    >>> a = [1, 2, 3]
    >>> del a[0] # should delete 1
    >>> a
    [2, 3]
    >>> del a[1] # This use to be the index for 2, but now `3` is at this index
    >>> a
    [2]
    

    【讨论】:

    • 哇你们回答得真快!我喜欢这个地方。
    【解决方案2】:

    一次删除一个。第一次删除将所有后续元素向左移动一个位置:

    In [3]: z = [1, 2, 3, 4, 5]
    
    In [5]: del z[1]
    
    In [6]: z
    Out[6]: [1, 3, 4, 5]
    
    In [7]: z[3]
    Out[7]: 5
    

    如果您将索引从最大到最小排列,则不会发生这种情况,因为没有删除会更改任何相关索引:

    In [18]: z = [1, 2, 3, 4, 5]
    
    In [19]: del z[3], z[1]
    
    In [20]: z
    Out[20]: [1, 3, 5]
    

    【讨论】:

      【解决方案3】:

      当您进行删除时,它们一次只发生一个,因此每次删除都会导致向右的值向左移动一个索引。

      z = [1, 2, 3, 4, 5]
      
      del z[1] # [1, X, 3, 4, 5] --> [1, 3, 4, 5]
      
      del z[3] # [1, 3, 4, X] --> [1, 3, 4]
      

      为了保持顺序,您应该做的是将删除从最大到最小的索引排序,这样就不会移动任何内容,即,

      del z[3]; del z[1]
      

      更好的是一次删除所有内容以完全避免问题:

      z = [1, 2, 3, 4, 5]
      del z[1::2]
      # returns [1, 3, 5]
      

      【讨论】:

      • 优秀的提示!感谢您的帮助!
      【解决方案4】:

      您看到这种行为的原因是 del z[1], z[3] 完全等同于将 del z[1]del z[3] 放在不同的行上。所以第一个del 语句将移动后续元素,z[3] 成为最后一个元素(5):

      >>> def del_test():
      ...     del z[1], z[3]
      ...
      >>> def del_test2():
      ...     del z[1]
      ...     del z[3]
      ...
      >>> del_test.__code__.co_code == del_test2.__code__.co_code
      True
      

      【讨论】:

        【解决方案5】:

        其他人提到你的代码有什么问题,我能真正理解你打算做什么的原因

        如果你想删除第 2 和第 4 个元素而不关心移位列表,你应该在一个单一的范围内完成,一个可能的解决方案是通过 List COMprehension

        def inplace_del(it, rng): 
            return [e for i, e in enumerate(it) if i not in set(rng)]
        inplace_del(z,(2,3))
        [1, 2, 5]
        y = xrange(1,6)
        inplace_del(y,(2,3))
        [1, 2, 5]
        

        更好的解决方案是使用 itertools

        >>> from itertools import count, compress
        >>> def in_del(it, rng):
            rng = set(rng)
            holes = (e not in rng for e in count(0))
            return compress(it, holes)
        
        >>> list(in_del(z,(2,3)))
        [1, 2, 5]
        >>> list(in_del(y,(2,3)))
        [1, 2, 5]
        >>> 
        

        【讨论】:

        • 如果 OP 不理解切片,那么很有可能使用 lambda 可能会有点远。无论如何,我想说以这种方式使用lambda 可能不是好的形式(恕我直言,lambda 通常应该保留用于传递给函数)。用正常的方式定义它,你就会有一个更惯用和有用的帖子。
        猜你喜欢
        • 1970-01-01
        • 2017-06-27
        • 2011-08-22
        • 2018-08-31
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        相关资源
        最近更新 更多