Python-数组切片
在SegmentFault上遇到一个问题,发现自己也不懂,找了资料弄懂了,翻译一下,加深印象。
基于维度的切片
Python的切片可以被用于数组,它基于每一个维度。例如有一个3x3的数组:
>>> a = reshape(arange(9), (3,3))
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
如果只使用[:]
表示一个从数组开始到结束的切片:
>>> print(a[:,:]) # 基于每一个维度,逗号前面是一个维度,后面是一个
[[0 1 2]
[3 4 5]
[6 7 8]]
也就是说,没有任何参数的切片[:]
和列表(list)的切片是一样的,可以理解为“取所有的索引”。但是数组切片和列表切片有一个重大的区别(见下文)。
既然是基于维度,那么我们可以这样取第二维的第二个元素:
>>> print(a[:,1])
[1 4 7]
Note that what was a “column” vector is now a “row” vector any “integer
slice” (as in the 1 in the example above) results in a returned array with
rank one less than the input array.
任何一个整数切分,即上面例子里面的1
,都会导致取得的切片比原来的数组少一个维度
译者注::
代表取遍第一维,1
相当于数组下标,即相当于做了平常常用的取数组元素second[1]
操作,所以就少了一个维度
再来几个例子
>>> print(a[:,0]) # 取所有第一维,第二维的第一个元素,即第一列
[0 3 6]
>>> print(a[:,0:2]) # 第一维的所有,第二维的[0,2)区间
[[0 1]
[3 4]
[6 7]]
数组切片和列表切片的区别
列表切片(slice of lists) 是原有列表的所取部分的复制
数组切片(slice of arrays) 只是提供一个所取数组元素的访问入口,如果想取得原有数组的copy,可以使用copy
方法,翻译太挫上例子:
>>> a = arange(20)
>>> b = a[3:8]
>>> c = a[3:8].copy()
>>> a[5] = -99
>>> print(b) # 修改a,a的切片b也变了,说明b并没有copy原数组
[ 3 4 -99 6 7]
>>> print(c) # c不会变,因为它是copy原来数组的
[3 4 5 6 7]
如果切片没有表面所有维度,没有表明的即表示取所有 操作:
A[1] == A[1,:] == A[1,:,:] # A是一个3维数组
间隔(步长)
python列表中取逆序列表可以这样somelist[::-1]
用到了切片的第三个参数step
即步长,当然数组切片也是可以的。不过Python 2.3之前的版本不支持此操作。
>>> a = reshape(arange(9),(3,3))
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> print(a[:, 0])
[0 3 6]
>>> print(a[0:3, 0])
[0 3 6]
>>> print(a[2::-1, 0]) #等效于print(a[::-1, 0])
[6 3 0]
切片的起始和终止索引的处理和列表是一样的,如上述代码的print(a[2::-1, 0])
当然,既然是一样的,你可以使用负数索引。
关键字...
还有一种数组切片的方法:使用关键字...
这个关键字表示:我想用多少:
取决于数组的维度有多少,我明确指定的索引将会在所有要取的索引的末尾(翻译得我都怀疑自己能不能看懂)。上例子:
三维数组 A[...,0]
–> A[:,:,0]a
四维 B[...,0]
–> B[:,:,:,0]
五维 C[...,0,...]
–>C[:,:,:,0,:]
注意这个五维的C
有两个...
,我指明了一个0
,它应该尽量靠后,所以就有了上面的结果
切片赋值
想要将一个数组切片的值整体赋给另一个同样大小的切片,这个操作很容易,但是如果这两个切片是同一个数组的,并且它们是重叠的,结果可能会让你惊讶
>>> n = arange(36)
>>> n[11:18] = n[7:14] # 将[7,14) 的值赋给 [11,18)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 7, 8, 9, 10, 7,
8, 9, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35])
注意到上面例子里面的特点了吗?
复制是从左向右的 即所有右边的值总是比左边的值晚赋值。
为了避免这种奇怪的结果(可能是你不想要的),你可以使用上面讲到的copy
方法。