为什么a = [1,2,3]返回[]为什么a [1:-1:-1]?

发布于 2025-01-23 20:30:12 字数 763 浏览 3 评论 0 原文

我观察到,如果 a 是带有Elements [1,2,3] 的列表(或Numpy数组),我要求 a [1: - - - 1:-1] ,然后我得到空列表。我希望获得 [2,1] ,假设切片跨越可从1到-1的索引,排除了最后一个值(不包括-1),那就是索引1和0。

实际行为可能具有一定的理由,但是当一个人需要从某些通用索引 i 开始到索引时,就可以使事情比预期的比预期更复杂。 i+m (排除)以相反的顺序。一个人会倾向于编写 a [i+m-1:i-1:-1] ,但如果 i 设置为0。对于所有 i ,但零看起来像是一种令人讨厌的矛盾。显然,有解决方法:

  1. 一个人可以编写 a [i+m-1-n:i-1-n:-1] 通过 -n 在其中 code > n 是数组长度;或者
  2. 可以写 a [i:i+m] [:: - 1]

但是,在情况1中,需要知道阵列长度显得不自然,如果在紧密的环中进行切片,则双重索引似乎是不是很合理的开销。

  • 有什么重要的原因是我不遗余力地行为是如此重要吗?

  • Numpy社区是否考虑过此问题?

  • 有比我想出的更好的解决方法了吗?

I am observing that if a is a list (or a numpy array) with elements [1,2,3] and I ask for a[1:-1:-1], then I get the empty list. I would expect to get [2,1] assuming that the slicing spans the indexes obtainable decrementing from 1 to -1 excluding the last value (that is excluding -1), that is indexes 1 and 0.

The actual behavior may have some justification but makes things more complex than expected when one needs to take a subarray of an array a starting from some generic index i to index i+m (excluded) in reverse order. One would tend to write a[i+m-1:i-1:-1] but this suddenly breaks if i is set to 0. The fact that it works for all i but zero looks like a nasty inconsistency. Obviously, there are workarounds:

  1. one could write a[i+m-1-n:i-1-n:-1] offsetting everything by -n where n is the array length; or
  2. one could write a[i:i+m][::-1].

However, in case 1 the need to know the array length appears rather unnatural and in case 2 the double indexing appears as a not very justified overhead if the slicing is done in a tight loop.

  • Is there any important reason that I am missing for which it is important that the behavior is as it is?

  • Has this issue been considered by the NumPy community?

  • Is there some better workaround than those I came up with?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

栀子花开つ 2025-01-30 20:30:12

Numpy从Python的序列索引中采用了这种行为,该规则被解释了这里(有关一些历史记录,请参见下文)。特别是脚注(5)读:

s 的切片来自 i to j 带有步骤 k 定义为带有项目的序列,索引 x = i + n*k ,以便 0< = n< (JI)/K 。换句话说,这些索引是 i i+k i+2*k i+3*k 等等,当达到 j 时停止(但永远不会包括 j )。当 k 为正时, i j 如果它们更大,则将其简化为 len(s)。当 k 为负时, i j 将减少到 len(s)-1 (如果它们更大)。如果 i j 被省略或 none ,它们成为“结束”值(结束取决于 k 的符号代码>)。注意, k 不能为零。如果 k 无,则将其视为 1


因此,这些索引是从乘数生成的 n ,但要受 0< = n< (JI)/K 。对于您的特定示例(JI)/K< 0 ,因此没有计算索引。

对于numpy数组 a [i:i+m] [:: - 1] 生成了基础数组的视图,即它的开销可以忽略不计,因此似乎是一个有效的解决方案。显然,它传达了意图,即“从某些通用索引 i 开始,以 a 的子阵列为子阵列 index i+m (排除)以相反的顺序“

另外,您可以使用作为停止参数,如果 i 为零:

a[i+m-1:(None if i==0 else i-1):-1]

历史

最初,Python通过 __ getslice __ /release/1.4/ref/ref3.html#hdr5“ rel =“ nofollow noreferrer”>在这里)不允许步骤参数,即它仅使用了2个argument form: a [[ a [ I:J] 。这是通过内置序列(例如 list )实现的。那时,在1995年左右,在矩阵sig (特殊兴趣组)。该前任实现了一个特定的 slice 类型,该类型也可以用来指定一个所谓的 stride (现在 step ),形式与今天非常相似 slice :例如 a [slice(none,none,none,2)] 。被要求扩展python的语法以允许今天知道的3型切片: a [:: 2] (请参阅eg 此线程)。这是以键入并将传递给 __ getItem __ ,而不是 __ getlice __ 。因此,当时, a [i:j] 被解析为 a .__ getlice __(i,j) a [i:j:k] 被解析为 a .__ getItem __(slice(i,j,k))。那时,数值python甚至允许使用2型切片,将第二个参数解释为大步(请参阅 docs ; eg a [i:-1] 等效于 a [i :: - 1] 对于数组对象 a )。阵列的索引是针对Python序列的索引如何工作的:包括开始索引,不包括停止索引(请参见在这里)。这也适用于负面大步(步骤),因此提供了今天可以观察到的行为。该决定可能是基于最小令人惊讶的原理//docs.python.org/release/1.5/lib/node10.html#section00315000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000来源程序。
花了很长时间,直到Python 2.3为内置类型实施了扩展的切片功能,包括一项步骤(请参阅
什么新功能注意,该文档的2.3版本包含一个错误的切片描述,该阶跃是固定用于2.4版本)。

Numpy has adopted this behavior from Python's sequence indexing for which the rules are explained here (for some history see below). Specifically footnote (5) reads:

The slice of s from i to j with step k is defined as the sequence of items with index x = i + n*k such that 0 <= n < (j-i)/k. In other words, the indices are i, i+k, i+2*k, i+3*k and so on, stopping when j is reached (but never including j). When k is positive, i and j are reduced to len(s) if they are greater. When k is negative, i and j are reduced to len(s) - 1 if they are greater. If i or j are omitted or None, they become “end” values (which end depends on the sign of k). Note, k cannot be zero. If k is None, it is treated like 1.

So the indices are generated from multipliers n subject to 0 <= n < (j-i)/k. For your specific example (j-i)/k < 0 and hence no indices are computed.

For Numpy arrays a[i:i+m][::-1] generates a view of the underlying array, i.e. it has negligible overhead and thus appears to be a valid solution. It clearly conveys the intent, namely "take a subarray of an array a starting from some generic index i to index i+m (excluded) in reverse order".

Alternatively, you can use None as the stop argument if i is zero:

a[i+m-1:(None if i==0 else i-1):-1]

History

Originally, Python implemented slicing syntax via __getslice__ (see also here) which didn't allow a step argument, i.e. it only used the 2-argument form: a[i:j]. This was implemented by built-in sequences such as list. Back then, around 1995, the predecessor of Numpy, Numerical Python, was developed and discussed within the MATRIX-SIG (special interest group). This predecessor implemented a specific Slice type which could be used to also specify a so called stride (now step) in a form very similar to today's slice: e.g. a[Slice(None, None, 2)]. It was asked to extend Python's syntax to allow for the 3-form slicing known today: a[::2] (see e.g. this thread). This got implemented in form of the slice type and would be passed to __getitem__ instead of __getslice__. So back then, a[i:j] was resolved as a.__getslice__(i, j) while a[i:j:k] was resolved as a.__getitem__(slice(i, j, k)). Back then, Numerical Python even allowed "reverse" slicing with the 2-form, interpreting the second argument as the stride (see the docs; e.g. a[i:-1] was equivalent to a[i::-1] for an array object a). Indexing of arrays was oriented at how indexing for Python sequences worked: including the start index, excluding the stop index (see here). This applied to negative stride (step) as well, hence providing the behavior that can be observed today. The decision was probably based on the principle of least surprise (for "standard" Python users).
It took a long time until Python 2.3 where the extended slicing feature including a step was implemented for the built-in types (see what's new and the docs; note that the 2.3 version of the docs contained a wrong description of slicing with step which was fixed for the 2.4 release).

所有深爱都是秘密 2025-01-30 20:30:12

-1作为索引具有特殊的含义[1],它被列表的最高=最后一个索引代替。
因此, a [1:-1:-1] 变为空的代码> A [1:2:-1] 是空的。

[1]实际上,Python中的所有负数索引都这样工作。 -1是指列表的最后一个元素,-2二次到二次,-3之前的元素,依此类推。

-1 as an index has a special meaning [1], it's replaced with the highest possible = last index of a list.
So a[1:-1:-1] becomes a[1:2:-1] which is empty.

[1] Actually, all negative indices in Python work like that. -1 means the last element of a list, -2 the second-to-last, -3 the one before that and so on.

薄荷→糖丶微凉 2025-01-30 20:30:12

列表[1:-1:-1] 表示列表[开始索引:end Index:jump]

列表中的索引:

数字 1 2 3
索引 0 1 2
索引 -3 -2 -1

因此,如果我们列出列表 a [1,2,3] 并找到 a [1:: -1:-1] 表示<代码>启动index = 1,end index = -1,jump = -1

so,列表穿越

索引1(IE编号= 2)到索引-1(IE编号= 3),但跳跃= -1(表示向后位置)

所以,返回一个空列表 ie []

List[1:-1:-1] means List[start index : end index : jump]

Indexing in List:

Number 1 2 3
Index 0 1 2
Index -3 -2 -1

So, if we take list a[1,2,3] and find list of a[1:-1:-1] means starting index = 1, ending index = -1, jump = -1

So, list traversing through the

index 1 (i.e. number=2) to index -1 (i.e. number=3) but jump = -1 (means backward position)

So, return an empty list i.e. []

岁月蹉跎了容颜 2025-01-30 20:30:12

正如其他人所指出的 -1 ,终点具有特殊的意思

In [66]: a=[1,2,3]

,将其缩回开始,最好使用 none

In [68]: a[1::-1]
Out[68]: [2, 1]
In [69]: a[1:None:-1]
Out[69]: [2, 1]

处理可以跨越边界的切片,任一方都可能很棘手:

In [75]: [a[i+2-1:i-1:-1] for i in range(4)]
Out[75]: [[], [3, 2], [3], []]

简化一点:

In [77]: [a[i+2:i:-1] for i in range(-1,3)]
Out[77]: [[], [3, 2], [3], []]

如果子句:

In [78]: [a[i+2:None if i<0 else i:-1] for i in range(-1,3)]
Out[78]: [[2, 1], [3, 2], [3], []]

As others noted -1 as end point has special meaning

In [66]: a=[1,2,3]

Slice back to the beginning is best done with None:

In [68]: a[1::-1]
Out[68]: [2, 1]
In [69]: a[1:None:-1]
Out[69]: [2, 1]

Working with slices that could cross boundaries, either side can be tricky:

In [75]: [a[i+2-1:i-1:-1] for i in range(4)]
Out[75]: [[], [3, 2], [3], []]

simplify a bit:

In [77]: [a[i+2:i:-1] for i in range(-1,3)]
Out[77]: [[], [3, 2], [3], []]

We can correct the lower boundary by using a if clause:

In [78]: [a[i+2:None if i<0 else i:-1] for i in range(-1,3)]
Out[78]: [[2, 1], [3, 2], [3], []]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文