【问题标题】:Reversing a list using slice notation使用切片表示法反转列表
【发布时间】:2011-08-18 03:11:38
【问题描述】:

在下面的例子中:

foo = ['red', 'white', 'blue', 1, 2, 3]

其中:foo[0:6:1] 将打印 foo 中的所有元素。但是,foo[6:0:-1] 将省略第 1 个或第 0 个元素。

>>> foo[6:0:-1]
[3, 2, 1, 'blue', 'white']

我知道我可以使用 foo.reverse() 或 foo[::-1] 反向打印列表,但我试图理解为什么 foo[6:0:-1] 不打印整个列表?

【问题讨论】:

  • 还要注意foo[7:None:-1] 的可能性:)
  • 在尝试理解切片表示法之前我从未使用过 python,我的问题是为什么 foo[6:0:-1] 没有抛出索引错误,python 不在乎吗?因为 6 索引在上面的示例数组中不可用。
  • @MubasharAhmad Slicing 没有索引,并且在超出范围时不会抛出任何错误。但是,索引在超出范围时确实会引发异常。

标签: python list syntax slice


【解决方案1】:

简而言之切片符号:

[ <first element to include> : <first element to exclude> : <step> ]

如果要在反转列表时包含第一个元素,请将中间元素留空,如下所示:

foo[::-1]

您还可以在此处找到一些关于 Python 切片的一般信息:
Explain Python's slice notation

【讨论】:

  • This:[ &lt;first element to include&gt; : &lt;first element to exclude&gt; : &lt;step&gt; ] 是我见过的对切片语法最清晰的解释。将其称为“要排除的第一个元素”确实可以清楚地看出发生了什么。
  • 负步数的负切片呢?我还是不明白。
  • 当您使用负索引作为&lt;first element to include&gt;&lt;first element to exclude&gt; 时,它从列表的后面开始索引,所以-1 是最后一个元素,-2 是倒数第二个元素等。例如,x[-1:-4:-1] 将以相反的顺序获得x 的最后三个元素。因此,您可能会将其解释为“从列表中的最后一个元素 (-1 &lt;first element to include&gt;) 向后移动每个元素 (-1 步骤),直到但不包括最后的第四个元素 (-4 &lt;first element to include&gt;)”。跨度>
  • 倒车时(即如果&lt;step&gt;-1),它有助于我思考&lt;first element to include, moving from right to left&gt;。因此,要以相反的顺序从列表中获取n“最左边”元素:foo[n-1::-1]。要以相反的顺序获取n“最右边”元素:foo[-1:-n-1:-1]
  • 如何让第一个元素排除“foo[0]之前的元素”?
【解决方案2】:

如果您在记住切片符号时遇到困难,可以尝试使用Hokey Cokey

[InOut摇摆不定]

[in包含的第一个元素:out的第一个元素:要使用的步骤]

YMMV

【讨论】:

    【解决方案3】:

    ...为什么 foo[6:0:-1] 不打印整个列表?

    因为中间值是独占,而不是包容,停止值。 interval notation 是[开始,停止)。

    这正是 [x]range 的工作原理:

    >>> range(6, 0, -1)
    [6, 5, 4, 3, 2, 1]
    

    这些是包含在结果列表中的索引,它们不包括第一项的 0。

    >>> range(6, -1, -1)
    [6, 5, 4, 3, 2, 1, 0]
    

    另一种看待它的方式是:

    >>> L = ['red', 'white', 'blue', 1, 2, 3]
    >>> L[0:6:1]
    ['red', 'white', 'blue', 1, 2, 3]
    >>> len(L)
    6
    >>> L[5]
    3
    >>> L[6]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: list index out of range
    

    索引 6 超出(准确地说是过去) L 的有效索引,因此将其从范围中排除为排除的停止值:

    >>> range(0, 6, 1)
    [0, 1, 2, 3, 4, 5]
    

    仍然为您提供列表中每个项目的索引。

    【讨论】:

    • range 可以,但 slice 不能,因为-1 是最后一个元素。所以l=[1, 2, 3]l[2:-1:-1] == []
    【解决方案4】:

    这个答案可能有点过时,但它可能对遇到同样问题的人有所帮助。 您可以获得具有任意结尾的反向列表 - 最多为 0 索引,应用第二个就地切片,如下所示:

    >>> L = list(range(10))
    >>> L
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> (start_ex, end) = (7, 0)
    >>> L[end:start_ex][::-1]
    [6, 5, 4, 3, 2, 1, 0]
    

    【讨论】:

    • 这实际上非常有用,因为您可以在所有情况下使用相同的语法。您不必将 0 视为特殊情况。
    • 这比 Python/numpy 的负切片默认行为更有意义,因为通常人们想要切片和/或反转与给定边缘对齐的图像或张量,而 Python/numpy 会丢失最后一行/列数据o_O。
    【解决方案5】:

    如果您使用负停止值,您可以让它工作。试试这个:

    foo[-1:-7:-1]
    

    【讨论】:

      【解决方案6】:

      使用

      >>>foo[::-1]
      

      这显示列表从结束元素到开始的反向,

      【讨论】:

        【解决方案7】:

        补充。以 2 步反转:

        A = [1,2,2,3,3]
        n = len(A)
        res = [None] * n
        mid = n//2 + 1 if n%2 == 1 else n//2
        
        res[0::2] = A[0:mid][::-1]
        res[1::2] = A[0:mid][::-1]
        print(res)
        

        [2, 3, 2, 3, 1]

        【讨论】:

          【解决方案8】:

          andrew-clark 的答案正式化一点:

          假设列表vv[n1:n2:n3] 切片。 n1 是初始位置,n2 是最终位置,n3 是步骤

          让我们用 Python 的方式写一些伪代码:

          n3 = 1  if (n3 is missing) else n3
          if n3==0:
             raise exception # error, undefined step
          

          第一部分:n3 正面

          if n3>0:
             slice direction is from left to right, the most common direction         
          
             n1 is left slice position in `v` 
             if n1 is missing: 
                n1 = 0   # initial position
             if n1>=0:
                n1 is a normal position
             else: 
               (-n1-1) is the position in the list from right to left 
          
             n2 is right slice position in `v` 
             if n2 is missing: 
                n2 = len(x)  # after final position
             if n2>=0:
                n2 is a normal final position (exclusive)
             else: 
                -n2-1 é the final position in the list from right to left 
                 (exclusive)
          

          第二部分:n3 否定

          else: 
            slice direction is from right to left (inverse direction)
          
            n1 is right slice position in `v` 
            if n1 is missing: 
               n1 = -1   # final position is last position in the list.
            if n1>=0:
               n1 is a normal position
            else: 
               (-n1-1) is the position in the list from right to left 
          
            n2 is  left slice position in `v` 
            if n2 is missing: 
               n2 = -len(x)-1   # before 1st character  (exclusive)
            if n2>=0:
               n2 is a normal final position (exclusive)
            else: 
               -n2-1 is the ending position in the list from right to left 
               (exclusive)
          

          现在原来的问题是:如何用切片符号反转列表?

          L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
          print(L(::-1)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
          

          为什么?
          n1 is missing and n3&lt;0 => n1=0
          n2 is missing and n3&lt;0 => n2 = -len(x)-1

          所以L(::-1) == L(-1:-11:-1)

          【讨论】:

          • 迄今为止我见过的全网最清晰的解释。不过我觉得可以稍微改进一下。 “(-n1-1) 是列表中从右到左的位置”是正确的,但我敢打赌大多数人认为这是从 0..size-1 开始的“正常”数组索引,所以 (-n1-1) 会变成 ((size-1)-(-n1-1))) 即(size+n1)
          【解决方案9】:

          这是一个非常好的问题,在我看来,以上答案都没有真正回答所提出的问题。部分原因是理智上诚实的答案可能会揭示 Python 类型系统的弱点。其他一些语言也存在同样的弱点。

          一个更理智的诚实答案可能是: Python 切片不能很好地泛化。

          准确地说,使用collection[begin:end] 可以在一个方向上遍历集合,但collection[end:begin:-1] 不起作用。它不起作用,因为第一个索引是0,但“第一个索引之前的索引”不是-1。因此,collection[end:-1:-1] 的评估结果并不符合我们的合理预期。

          [first to include : first to exclude : step] 的解释有缺陷。如果“第一个排除”是第一个元素之前的那个,则不能以与想要包含相同的第一个元素的情况相同的方式表达它。

          总而言之,你并不疯狂地期待一般性,它只是不存在。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-03-08
            • 2020-03-10
            • 2016-03-09
            • 1970-01-01
            • 1970-01-01
            • 2011-10-27
            • 1970-01-01
            • 2023-04-07
            相关资源
            最近更新 更多