|
本帖最后由 草帽路飞UU 于 2022-12-13 15:47 编辑
前言
Python 提供了许多方法来创建二维列表/数组。然而,但大多数人不知道这些创建方法的区别。我也不知道,所以本文就来介绍一下关于二维数组的有趣地方。
创建一维数组/列表
先让我们先来看看创建大小为 N、初始化值为 0 的一维数组(列表)的常见方法。
原始方法
array1 = [0] * 5
array1
[0, 0, 0, 0, 0]
用列表推导式
array2 = [0 for i in range(5)]
array2
[0, 0, 0, 0, 0]
在 Python3 的 IDLE 操作如下:
创建二维数组
二维数组是一个线性存储在内存中的二维数据结构。这意味着它有两个维度,行和列,因此它也代表一个矩阵。
通过线性数据结构,我们的意思是元素被线性地放置在内存中,并且每个元素都与它的上一个和下一个元素相连。
如果我们把二维数组想象成表格的形式,但实际上,元素是线性地存储在内存中的。二维数组的元素在内存中是连续排列的。这意味着,如果一个元素出现在当前的内存地址,那么下一个元素将被放置在下一
个内存地址。这种类型的存储使数组可以随机访问。这意味着我们可以独立访问数组中的任何元素。就像下图:
在 Python 中创建二维数组,不像 C++ 和 Java 中那样简单,直接用两个 [][] 中括号。先来看一下 Java 中创建二维数组的方式。
先来看 Java 中创建二维数组的方式,Java 中创建二维数组的格式:
type arrayName[][];
type [][]arrayName;
比如,定义一个 4 行 2 列的整型二维数组:
int[][] arrayName = new int[4][2]; // // 2D integer array with 4 rows and 2 columns
创建一个 Python 二维数组的错误
也想模仿一下 Java,奈何只能得到一个语法错误:
>>> twoD_array = [][]
SyntaxError: invalid syntax
抱歉,行不通。但是可以这样:
>>> twoD_array = [[]]
>>> twoD_array
[[]]
就像下图:
但这种方式不一一定符合你对二维数组的期望,后面会介绍。如果想要以一种更像 Java 的方式,可以使用这种方式:
matrix = []
for i in range(5):
row = []
for j in range(5):
row.append(0)
matrix.append(row)
print(matrix)
输出:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
所以,为了创建一个二维数组,其本质就是用嵌套类别的方式,就像下面这样:
>>> li = [[1,2,3], [4,5,6]]
>>> li
[[1, 2, 3], [4, 5, 6]]
这样又太麻烦,我想有没有更好的方法。
方法一
像创建一维数组那样:
>>> rows, cols = (2, 3)
>>> arr = [[0] * cols] * rows
>>> arr
[[0, 0, 0], [0, 0, 0]]
方法二
利用列表推导式:
>>> arr = [[0 for i in range(cols)] for j in range(rows)]
>>> arr
[[0, 0, 0], [0, 0, 0]]
两种方式都提供与现在相同的输出。
更改一下二维数组的元素看看
之前说过,这种方式不一定能满足你对二维数组的期望,现在让我们更改方法一和方法二的数组中的元素:
# 方法一
>>> rows, cols = (2, 3)
>>> arr = [[0] * cols] * rows
>>> arr[0][0] = 1
>>> for row in arr:
... print(row)
...
[1, 0, 0]
[1, 0, 0]
奇怪的事情发生了,明明我只改变了 arr[0][0],我希望的是第一行的第一个元素更改为 1,但结果却是每行的第一个元素更改为 1。
再来看一下方法二:
# 方法二
>>> rows, cols = (2, 3)
>>> arr = [[0 for i in range(cols)] for j in range(rows)]
>>> arr[0][0] = 1
>>> for row in arr:
... print(row)
...
[1, 0, 0]
[0, 0, 0]
方法二正是我想要的答案。
什么原因呢?
我这里就简单解释一下:
方法一中,Python 不会创建 2 个 list 对象,而是仅创建一个 list 对象,并且数组 arr 的所有索引都指向同一列表对象( list ),如图所示。
方法二,会创建 2 个单独的列表对象,如下图:
我们可以通过 is() 函数来检查上面的方法一和方法二是否指向同一个对象:
可以看到通过方法二创建的数组 arr1[0] 和 arr1[1] 结果为 False。
>>> rows, cols = (5, 5)
>>> arr1 = [[0 for i in range(cols)] for j in range(rows)]
>>> print(arr1[0] is arr1[1])
False
而方法一结果为 True,说明是同一对象。
>>> arr2 = [[0]*cols]*rows
>>> print(arr2[0] is arr2[1])
True
所以正确的创建二维数组的方式就是用方法二, 也就是:
rows, cols = (5, 5)
arr2 = [[0 for i in range(cols)] for j in range(rows)]
一个 5 行 5 列的二维数组就创建成功:
>>> for row in arr2:
... print(row)
...
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
不过,还没完,还有一点,我们发现 i 和 j 变量好像都没使用,所以我们用单下划线 _ 进行变量舍弃:
rows, cols = (5, 5)
arr2 = [[0 for _ in range(cols)] for _ in range(rows)] # 创建一个正确的5行5列的数组
在 Python 中,单个独立下划线是用作一个名字,来表示某个变量是临时的或无关紧要的。
方法三
最后,如果想要一个支持数学运算的二维数组,推荐使用 numpy 包。官网点此处。
numpy 中的矩阵操作最常使用的是二维数组类型。有很多方法可以创建一个新的数组;其中最有用的是 zeros 函数,它接受一个形状参数并返回一个给定形状的数组,其值被初始化为零。
>>> import numpy
>>> numpy.zeros(5,5)
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
>>>
>>> numpy.empty((5,5)) # allocate, but don't initialize
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
>>>
>>> numpy.ones((5,5)) # initialize with ones
array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
总结
本文的创造灵感来自于学习 Python 的列表时,想到 Java 中的数组和二维数组,就想上网搜搜 Python 二维数组的定义方式,然后就找到了 StackOverflow 上的这一个问题:How to define a two-
dimensional array?,在这个问题的回答下,抱着玩一玩的心态写完了这篇文章。
至此,我们终于能够正确创建一个 Python 的二维数组了。对,就是它:
arr2 = [[0 for _ in range(5)] for _ in range(5)] # 创建一个正确的5行5列的数组
本文介绍了 Python 中的二维数组的三种创建方式,我们都知道数组是线性数据结构,包含了连续内存空间中相同数据类型的元素,所以我们能很方便的检索到数组中的每一个值,二维数组也不例外。通
过 arr[row][cols] 能很方便的获取二维数组中的元素。
|
|