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

时间:2021-03-25 21:34:54

Bear with me while I explain my question. Skip down to the bold heading if you already understand extended slice list indexing.

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

In python, you can index lists using slice notation. Here's an example:

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

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

You can also include a stride, which acts like a "step":

你还可以包括一个步幅,它就像一个“步骤”:

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

The stride is also allowed to be negative, meaning the elements are retrieved in reverse order:

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

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

But wait! I wanted to see [4, 3, 2, 1, 0]. Oh, I see, I need to decrement the start and end indices:

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

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

What happened? It's interpreting -1 as being at the end of the array, not the beginning. I know you can achieve this as follows:

发生了什么?它将-1解释为位于数组的末尾,而不是开头。我知道你可以达到以下目的:

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

But you can't use this in all cases. For example, in a method that's been passed indices.

但是你无法在所有情况下使用它。例如,在已传递索引的方法中。

My question is:

Is there any good pythonic way of using extended slices with negative strides and explicit start and end indices that include the first element of a sequence?

是否有任何好的pythonic方法使用具有负步幅的扩展切片以及包含序列的第一个元素的显式开始和结束索引?

This is what I've come up with so far, but it seems unsatisfying.

这是我到目前为止所提出的,但似乎并不令人满意。

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

9 个解决方案

#1


It is error-prone to change the semantics of start and stop. Use None or -(len(a) + 1) instead of 0 or -1. The semantics is not arbitrary. See Edsger W. Dijkstra's article "Why numbering should start at zero".

更改启动和停止的语义很容易出错。使用无或 - (len(a)+ 1)而不是0或-1。语义不是任意的。请参阅Edsger W. Dijkstra的文章“为什么编号应该从零开始”。

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

Or

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

Or

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

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

If i or j is negative, the index is relative to the end of the string: len(s) + i or len(s) + j is substituted. But note that -0 is still 0.

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

that is why len(range(10)[4:-1:-1]) == 0 because it is equivalent to range(10)[4:9:-1].

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

#2


Ok, I think this is probably as good as I will get it. Thanks to Abgan for sparking the idea. This relies on the fact that None in a slice is treated as if it were a missing parameter. Anyone got anything better?

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

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

edit: check for start==-1, not 0

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

This is still not ideal, because you're clobbering the usual behavior of -1. It seems the problem here is two overlapping definitions of what's supposed to happen. Whoever wins takes away otherwise valid invocations looking for the other intention.

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

#3


[ A[b] for b in range(end,start,stride) ]

Slower, however you can use negative indices, so this should work:

较慢,但你可以使用负指数,所以这应该工作:

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

I realize this isn't using slices, but thought I'd offer the solution anyway if using slices specifically for getting the result isn't a priority.

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

#4


I believe that the following doesn't satisfy you:

我相信以下内容并不能满足您:

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

or does it? :-)

还是吗? :-)

#5


But you can't use that if you are storing your indices in variables for example.

但是,如果要将索引存储在变量中,则无法使用它。

Is this satisfactory?

这令人满意吗?

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

#6


As you say very few people fully understand everything that you can do with extended slicing, so unless you really need the extra performance I'd do it the "obvious" way:

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

rev_subset = reversed(data[start:stop])

rev_subset = reverse(data [start:stop])

#7


a[4::-1]

Example:

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

The reason is that the second term is interpreted as "while not index ==". Leaving it out is "while index in range".

原因是第二项被解释为“而不是索引==”。离开它是“在范围内的指数”。

#8


I know this is an old question, but in case someone like me is looking for answers:

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

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

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

#9


You can use a slice(start, stop, step) object, which is such that

您可以使用切片(开始,停止,步骤)对象,这样就可以了

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

is the same as

是相同的

print a[start : stop : step]

and, moreover, you can set any of the arguments to None to indicate nothing in between the colons. So in the case you give, you can use slice(4, None, -1).

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

#1


It is error-prone to change the semantics of start and stop. Use None or -(len(a) + 1) instead of 0 or -1. The semantics is not arbitrary. See Edsger W. Dijkstra's article "Why numbering should start at zero".

更改启动和停止的语义很容易出错。使用无或 - (len(a)+ 1)而不是0或-1。语义不是任意的。请参阅Edsger W. Dijkstra的文章“为什么编号应该从零开始”。

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

Or

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

Or

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

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

If i or j is negative, the index is relative to the end of the string: len(s) + i or len(s) + j is substituted. But note that -0 is still 0.

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

that is why len(range(10)[4:-1:-1]) == 0 because it is equivalent to range(10)[4:9:-1].

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

#2


Ok, I think this is probably as good as I will get it. Thanks to Abgan for sparking the idea. This relies on the fact that None in a slice is treated as if it were a missing parameter. Anyone got anything better?

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

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

edit: check for start==-1, not 0

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

This is still not ideal, because you're clobbering the usual behavior of -1. It seems the problem here is two overlapping definitions of what's supposed to happen. Whoever wins takes away otherwise valid invocations looking for the other intention.

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

#3


[ A[b] for b in range(end,start,stride) ]

Slower, however you can use negative indices, so this should work:

较慢,但你可以使用负指数,所以这应该工作:

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

I realize this isn't using slices, but thought I'd offer the solution anyway if using slices specifically for getting the result isn't a priority.

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

#4


I believe that the following doesn't satisfy you:

我相信以下内容并不能满足您:

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

or does it? :-)

还是吗? :-)

#5


But you can't use that if you are storing your indices in variables for example.

但是,如果要将索引存储在变量中,则无法使用它。

Is this satisfactory?

这令人满意吗?

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

#6


As you say very few people fully understand everything that you can do with extended slicing, so unless you really need the extra performance I'd do it the "obvious" way:

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

rev_subset = reversed(data[start:stop])

rev_subset = reverse(data [start:stop])

#7


a[4::-1]

Example:

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

The reason is that the second term is interpreted as "while not index ==". Leaving it out is "while index in range".

原因是第二项被解释为“而不是索引==”。离开它是“在范围内的指数”。

#8


I know this is an old question, but in case someone like me is looking for answers:

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

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

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

#9


You can use a slice(start, stop, step) object, which is such that

您可以使用切片(开始,停止,步骤)对象,这样就可以了

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

is the same as

是相同的

print a[start : stop : step]

and, moreover, you can set any of the arguments to None to indicate nothing in between the colons. So in the case you give, you can use slice(4, None, -1).

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