以负步幅进入序列开头的扩展切片

Extended slice that goes to beginning of sequence with negative stride

提问人:recursive 提问时间:12/30/2008 最后编辑:recursive 更新时间:4/13/2014 访问量:2909

问:

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

在 python 中,您可以使用切片表示法为列表编制索引。下面是一个示例:

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

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

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

步幅也允许为负数,这意味着元素以相反的顺序检索:

>>> 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 列表 切片

评论


答:

0赞 Charlie Martin 12/30/2008 #1
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 index in range”。

评论

0赞 recursive 12/30/2008
我在问题中提到了这一点。但是,例如,如果您将索引存储在变量中,则不能使用它。
1赞 Abgan 12/30/2008 #2

我相信以下内容不能让您满意:

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

或者是吗?:-)

评论

0赞 recursive 12/30/2008
我曾考虑过,要求两个单独的案例似乎是不必要的。但你给了我一个主意......
2赞 recursive 12/30/2008 #3

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

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

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

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

评论

1赞 jfs 1/2/2009
您可以替换为 。查看 stackoverflow.com/questions/399067/...None-len(a) + start
0赞 maxpolk 12/28/2012
需要明确的是,J.F. Sebastian 有最好的解决方案。完全消除条件并始终使用负索引,如 aList[end:start-len(aList):negativeStep]。没有对具有负步骤的扩展切片进行特殊检查。
2赞 codelogic 12/30/2008 #4
[ A[b] for b in range(end,start,stride) ]

速度较慢,但是您可以使用负指数,因此这应该有效:

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

我意识到这不是使用切片,但我想如果专门使用切片来获得结果不是优先事项,我无论如何都会提供解决方案。

评论

0赞 max 8/21/2011
但问题是它不适用于字符串。您需要为每种序列类型(字符串、列表等)创建单独的代码
1赞 Alex Coventry 12/30/2008 #5

如果你是 将索引存储在变量中 例。

这令人满意吗?

>>> a = range(10)
>>> start = 0
>>> end = 4
>>> a[4:start-1 if start > 0 else None:-1]
[4, 3, 2, 1, 0]
5赞 jfs 12/30/2008 #6

更改 和 的语义很容易出错。使用 或 代替 或 。语义不是任意的。参见 Edsger W. Dijkstra 的文章“为什么编号应该从零开始”。startstopNone-(len(a) + 1)0-1

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

s 是序列时,s[i:j:k] 中的负索引被特殊处理:

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

这就是为什么因为它等价于 .len(range(10)[4:-1:-1]) == 0range(10)[4:9:-1]

评论

0赞 huggie 4/13/2014
那么,以负步幅开始和停止会发生什么?开始和结束的语义是否发生了变化(尤其是否定的?我不明白。
0赞 jfs 4/13/2014
@huggie:如果 then 应该更大,则结果为空。step < 0startstop
1赞 James Antill 12/30/2008 #7

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

rev_subset = reversed(data[start:stop])

评论

0赞 max 8/21/2011
不仅很少有人理解切片,而且由于“减去意味着从最后开始计数”的约定,扩展的切片也被 f***ed 了。我从来不会使用扩展切片。
0赞 xiao-yu 1/5/2011 #8

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

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

>>> A[4:1:-1]
[4, 3, 2]
0赞 Andrew Jaffe 1/5/2011 #9

您可以使用一个对象,该对象是这样的slice(start, stop, step)

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

print a[start : stop : step]

此外,您可以将任何参数设置为在冒号之间不表示任何内容。因此,在您给出的情况下,您可以使用.Noneslice(4, None, -1)