【问题标题】:Extended slice that goes to beginning of sequence with negative stride以负步幅进入序列开头的扩展切片
【发布时间】:2010-09-28 18:47:30
【问题描述】:

请耐心等待我解释我的问题。如果您已经了解扩展切片列表索引,请跳至粗体标题。

在 python 中,您可以使用切片表示法对列表进行索引。这是一个例子:

>>> A = list(range(10))
>>> A[0:5]
[0, 1, 2, 3, 4]

您还可以包含一个步幅,其作用类似于“步”:

>>> A[0:5:2]
[0, 2, 4]

stride 也允许为负数,表示以相反的顺序检索元素:

>>> A[5:0:-1]
[5, 4, 3, 2, 1]

但是等等!我想看看[4, 3, 2, 1, 0]。哦,我明白了,我需要减少开始和结束索引:

>>> A[4:-1:-1]
[]

发生了什么?它将 -1 解释为位于数组的末尾,而不是开头。我知道您可以通过以下方式实现:

>>> A[4::-1]
[4, 3, 2, 1, 0]

但您不能在所有情况下都使用它。例如,在已传递索引的方法中。

我的问题是:

有没有什么好的 Pythonic 方式来使用具有负步幅的扩展切片以及包含序列第一个元素的显式开始和结束索引

这是我目前想出的,但似乎并不令人满意。

>>> A[0:5][::-1]
[4, 3, 2, 1, 0]

【问题讨论】:

    标签: python list slice


    【解决方案1】:

    更改startstop 的语义很容易出错。使用None-(len(a) + 1) 而不是0-1。语义不是任意的。请参阅 Edsger W. Dijkstra 的文章 "Why numbering should start at zero"

    >>> a = range(10)
    >>> start, stop, step = 4, None, -1
    

    或者

    >>> start, stop, step = 4, -(len(a) + 1), -1
    >>> a[start:stop:step]
    [4, 3, 2, 1, 0]
    

    或者

    >>> s = slice(start, stop, step)
    >>> a[s]
    [4, 3, 2, 1, 0]
    

    When s is a sequence the negative indexes in s[i:j:k] are treated specially:

    如果ij 为负数,则索引相对于字符串的末尾: len(s) + ilen(s) + j 被替换。但请注意,-0 仍然是 0

    这就是len(range(10)[4:-1:-1]) == 0 的原因,因为它等同于range(10)[4:9:-1]

    【讨论】:

    • 那么负步幅开始和停止会发生什么? start 和 end 的语义是否改变了(尤其是否定的?)我不明白。
    • @huggie: 如果step < 0 那么start 应该更大 然后stop 否则结果为空。
    【解决方案2】:

    好的,我想这可能和我能得到的一样好。感谢 Abgan 激发了这个想法。这依赖于切片中的 None 被视为缺少参数的事实。有人有更好的吗?

    def getReversedList(aList, end, start, step):
        return aList[end:start if start!=-1 else None:step]
    

    编辑:检查start==-1,而不是0

    这仍然不理想,因为您破坏了 -1 的通常行为。似乎这里的问题是应该发生的事情的两个重叠定义。无论谁获胜,都会取消寻找其他意图的其他有效调用。

    【讨论】:

    • 您可以将None 替换为-len(a) + start。见stackoverflow.com/questions/399067/…
    • 明确地说,J.F. Sebastian 有最好的解决方案。完全消除条件并始终使用负索引,如 aList[end:start-len(aList):negativeStep]。没有对带有负步长的扩展切片进行特殊检查。
    【解决方案3】:
    [ A[b] for b in range(end,start,stride) ]
    

    较慢,但是您可以使用负索引,所以这应该可以:

    [ A[b] for b in range(9, -1, -1) ]
    

    我意识到这不是使用切片,但我想如果使用切片专门用于获取结果不是优先事项,我还是会提供解决方案。

    【讨论】:

    • 但问题是它不适用于字符串。您需要为每种序列类型(字符串、列表等)创建单独的代码
    【解决方案4】:

    我认为以下内容不能满足您:

    def getReversedList(aList, end, start, step):
        if step < 0 and start == 0:
             return aList[end::step]
        return aList[end:start:step]
    

    还是这样? :-)

    【讨论】:

    • 我曾考虑过,要求两个单独的案例似乎是不必要的。但是你给了我一个想法……
    【解决方案5】:

    But 你不能使用它,如果你是 将索引存储在变量中 例子。

    这样满意吗?

    >>> a = range(10)
    >>> start = 0
    >>> end = 4
    >>> a[4:start-1 if start > 0 else None:-1]
    [4, 3, 2, 1, 0]
    

    【讨论】:

      【解决方案6】:

      正如你所说,很少有人完全理解扩展切片所能做的一切,所以除非你真的需要额外的性能,否则我会以“明显”的方式来做:

      rev_subset = reversed(data[start:stop])

      【讨论】:

      • 不仅很少有人理解切片,而且由于“减号表示从末尾开始计数”的约定,扩展切片也被搞砸了。我永远不会使用扩展切片。
      【解决方案7】:
      a[4::-1]
      

      例子:

      Python 2.6 (r26:66714, Dec  4 2008, 11:34:15) 
      [GCC 4.0.1 (Apple Inc. build 5488)] on darwin
      Type "help", "copyright", "credits" or "license" for more information.
      >>> a = list(range(10))
      >>> a
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      >>> a[4:0:-1]
      [4, 3, 2, 1]
      >>> a[4::-1]
      [4, 3, 2, 1, 0]
      >>> 
      

      原因是第二个词被解释为“while not index ==”。省略它是“当索引在范围内”。

      【讨论】:

      • 我在问题中提到了这一点。但是,例如,如果您将索引存储在变量中,则不能使用它。
      【解决方案8】:

      我知道这是一个老问题,但万一像我这样的人正在寻找答案:

      >>> A[5-1::-1]
      [4, 3, 2, 1, 0]
      
      >>> A[4:1:-1]
      [4, 3, 2]
      

      【讨论】:

        【解决方案9】:

        您可以使用slice(start, stop, step) 对象,即

        s=slice(start, stop, step)
        print a[s]
        

        一样
        print a[start : stop : step]
        

        此外,您可以将任何参数设置为None 以指示冒号之间的任何内容。所以在你给的情况下,你可以使用slice(4, None, -1)

        【讨论】:

          猜你喜欢
          • 2019-08-31
          • 1970-01-01
          • 2017-06-06
          • 2013-01-09
          • 2016-12-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多