Python中有关数据结构索引和切片引起的Bug

  • 一维数据索引和切片
    • 一维数组
    • 一维列表
  • 二维数据的索引和切片
    • 二维数组
    • 二维(错误)列表

一维数据索引和切片

一维数组

对于一维数据进行索引和切片操作,大家都比较熟悉通过下面代码进行实现

import numpy as npdata = np.random.randn(5)print(data)print(data[2:5])#一维数组切片操作,获取索引2到4的数据print(data[3]) #一维数组索引操作,获取索引为3的数据

一维列表

对于一维列表元组等相关结果的索引和切片操作,与一维数组类似

ls = [1, 2, 3, 4, 5]print(ls)print(ls[3:5]) #一维列表切片操作,获取索引2到4的数据print(ls[3])#一维列表索引操作,获取索引为3的数据

二维数据的索引和切片

对于二维数据的索引和切片就有一些需要注意的事项了,如果一不小心可能会出现意料之外的Bug

二维数组

import numpy as npdata = np.random.randn(55)print(data)print(data[1:3, 2:4])#二维数组切片操作,获取索引1到2行2到3列的数据print(data[3, 2]) #二维数组索引操作,获取索引为3行2列的数据print(data[3][2]) #二维数组索引操作,获取索引为3行2列的数据print(data[1:3])#二维数组切片操作,获取索引为1到2行所有列的数据print(data[:, 2:4])#二维数组切片操作,获取索引为2到3列的所有行数据print(data[1:3][2:4]) #想要获取1到2行和2到3列数据,单数会引发bug


上面就是二维数组索引和切片的大部分操作,对于索引来说可以使用data[3, 2]也可以使用data[3][2]操作,这两个获取的结果是一致的,那对于切片操作来说为啥data[1:3, 2:4]和操作data[1:3][2:4]不仅获取的结果不一致而且data[1:3][2:4]获取到的数据为空。对于初学者来说可能很难理解这样的情况,不知道bug的原因。但是换个索引行列data[1:3][0:2]会获得下面结果

这个情况就比较让人费解了,索引1到2行2到3列的数据获取为空,索引1到2行0到1列反而可以得到数据。问题是二维数组的大小为5×5,无论哪种索引都没超过数组范围啊。但是仔细查看索引数据data[1:3][0:2]发现得到的并不是1到2行0到1列的数据,而是1到2行所有列的数据。什么原因导致的呢?因为[1:3][0:2]这样的索引方式并不是向我们想的那样获取1到2行0到1列的数据。而是两次行索引操作,第一次获取1到2行所有列数据,数据大小为2×5,第二次获取0到1行的所有列数据。这样并没有列索引的操作,因此无法获取我们想要的数据。那为啥data[1:3][2:4]索引的数据为空呢?因为第一次行索引得到2×5大小的二维数组,第二次行索引获取2到3行的数据超出了数据大小范围,因此获得的数据为空。所以对于二维数组data[1:3][2:4]不是对相应的行列索引切片,而是进行了两次行切片。切记不要搞错,不然获取数据为空引发的bug还好解决,万一获取错误数据可能就不容易发现Bug了。
那为何进行索引操作data[3, 2]和data[3][2]都可以正常获取数据呢?(PS:要不是有这样一个索引操作,估计大家就不会使用类似的切片操作了)因为第一次行索引获得第3行数据,大小为1×5,第二次获取第3行中的第2个数据因此可以正常获取到3行2列的数据。

二维(错误)列表


对于二维列表或者元组进行索引或者切片操作,可能会引发以上Bug

zarten = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]print(zarten)print(zarten[3][2])print(zarten[1:3][0:2])print(zarten[1:3, 2:4])#错误切片操作print(zarten[3, 2])#错误索引操作


为何二维列表或元组进行二维数组类似的索引和切片操作就会出现以上报错,因为列表和元组没有二维数据,有同学觉得上面5×5的不就是二维列表吗?其实不是,这只是个列表中的列表,并无行列区分。比如列表中每个列表的元素个数可以不同,第一个列表中可以有5个元素,第二个列表中可以有3个元素等等,因此列表、元组并不能像我们认为的二维数组那样进行行列索引、切片操作。但是如果列表中的每个列表元素个数以及数据类型都一致,可以通过将列表转换为NumPy数组进行行列索引、切片操作。

import numpy as npdata = np.array(data)

祝好~