📜  Python|正确使用二维数组/列表

📅  最后修改于: 2022-05-13 01:54:21.704000             🧑  作者: Mango

Python|正确使用二维数组/列表

Python提供了许多创建二维列表/数组的方法。然而,人们必须知道这些方式之间的区别,因为它们会在代码中产生难以追踪的复杂性。让我们从创建以 0 初始化的大小为 N 的一维数组的常用方法开始。
方法 1a

Python3
# First method to create a 1 D array
N = 5
arr = [0]*N
print(arr)


Python3
# Second method to create a 1 D array
N = 5
arr = [0 for i in range(N)]
print(arr)


Python3
# Using above first method to create a
# 2D array
rows, cols = (5, 5)
arr = [[0]*cols]*rows
print(arr)


Python3
# Using above second method to create a
# 2D array
rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]
print(arr)


Python3
# Using above second method to create a
# 2D array
rows, cols = (5, 5)
arr=[]
for i in range(rows):
    col = []
    for j in range(cols):
        col.append(0)
    arr.append(col)
print(arr)


Python3
# Python 3 program to demonstrate working
# of method 1 and method 2.
 
rows, cols = (5, 5)
 
# method 2a
arr = [[0]*cols]*rows
 
# lets change the first element of the
# first row to 1 and print the array
arr[0][0] = 1
 
for row in arr:
    print(row)
# outputs the following
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
 
# method 2b
arr = [[0 for i in range(cols)] for j in range(rows)]
 
# again in this new array lets change
# the first element of the first row
# to 1 and print the array
arr[0][0] = 1
for row in arr:
    print(row)
 
# outputs the following as expected
#[1, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]


Python3
rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]


Python3
rows, cols = (5, 5)
# method 2b
arr = [[0 for i in range(cols)] for j in range(rows)]
 
# check if arr[0] and arr[1] refer to
# the same object
print(arr[0] is arr[1]) # prints False
 
# method 2a
arr = [[0]*cols]*rows
 
# check if arr[0] and arr[1] refer to
# the same object
# prints True because there is only one
# list object being created.
print(arr[0] is arr[1])


输出:
[0, 0, 0, 0, 0]

方法 1b

Python3

# Second method to create a 1 D array
N = 5
arr = [0 for i in range(N)]
print(arr)
输出:
[0, 0, 0, 0, 0]

扩展上述内容,我们可以通过以下方式定义二维数组。
方法 2a

Python3

# Using above first method to create a
# 2D array
rows, cols = (5, 5)
arr = [[0]*cols]*rows
print(arr)
输出:
[[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]]

方法 2b

Python3

# Using above second method to create a
# 2D array
rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]
print(arr)
输出:
[[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]]

方法 2c

Python3

# Using above second method to create a
# 2D array
rows, cols = (5, 5)
arr=[]
for i in range(rows):
    col = []
    for j in range(cols):
        col.append(0)
    arr.append(col)
print(arr)
输出:
[[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]]

到目前为止,这两种方式都给出了看似相同的输出。让我们更改方法 2a 和方法 2b 的数组中的一个元素。

Python3

# Python 3 program to demonstrate working
# of method 1 and method 2.
 
rows, cols = (5, 5)
 
# method 2a
arr = [[0]*cols]*rows
 
# lets change the first element of the
# first row to 1 and print the array
arr[0][0] = 1
 
for row in arr:
    print(row)
# outputs the following
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]
 
# method 2b
arr = [[0 for i in range(cols)] for j in range(rows)]
 
# again in this new array lets change
# the first element of the first row
# to 1 and print the array
arr[0][0] = 1
for row in arr:
    print(row)
 
# outputs the following as expected
#[1, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
#[0, 0, 0, 0, 0]
输出:
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]

我们希望只有第一行的第一个元素更改为 1,但在方法 2a 中每行的第一个元素都更改为 1。这种特殊的功能是因为Python使用我们将尝试理解的浅表。
在方法 1a 中, Python不会创建 5 个整数对象,而是仅创建一个整数对象,并且数组 arr 的所有索引都指向同一个 int 对象,如图所示。

一维浅数组表示

如果我们将第 0 个索引分配给另一个整数,比如 1,则创建一个值为 1 的新整数对象,然后第 0 个索引现在指向这个新的 int 对象,如下所示

一维浅数组改变值

类似地,当我们创建一个二维数组为“arr = [[0]*cols]*rows”时,我们本质上是对上述类比的扩展。
1. 只创建一个整数对象。
2. 创建一个 1d 列表,它的所有索引都指向点 1 中的同一个 int 对象。
3. 现在,arr[0]、arr[1]、arr[2] ...。 arr[n-1] 都指向上面第 2 点中的同一个列表对象。
上面的设置可以在下图中可视化。

二维浅数组表示

现在让我们将“arr”第一行中的第一个元素更改为
arr[0][0] = 1
=> arr[0] 指向我们上面创建的单个列表对象。(记住 arr[1], arr[2] …arr[n-1] 也都指向同一个列表对象)
=> arr[0][0] 的赋值将创建一个值为 1 的新 int 对象,并且 arr[0][0] 现在将指向这个新的 int 对象。(arr[1][0] 也是如此, arr[2][0] …arr[n-1][0])
这可以在下图中清楚地看到。

二维浅数组已更改

因此,当像这样创建 2d 数组时,更改某一行的值将影响所有行,因为数组的所有行都引用了一个整数对象和一个列表对象。
正如您所料,追踪由这种浅表使用引起的错误是很困难的。因此,声明二维数组的更好方法是

Python3

rows, cols = (5, 5)
arr = [[0 for i in range(cols)] for j in range(rows)]
输出:

与方法 2a 不同,此方法创建 5 个单独的列表对象。检查这一点的一种方法是使用“is”运算符来检查两个操作数是否引用同一个对象。

Python3

rows, cols = (5, 5)
# method 2b
arr = [[0 for i in range(cols)] for j in range(rows)]
 
# check if arr[0] and arr[1] refer to
# the same object
print(arr[0] is arr[1]) # prints False
 
# method 2a
arr = [[0]*cols]*rows
 
# check if arr[0] and arr[1] refer to
# the same object
# prints True because there is only one
# list object being created.
print(arr[0] is arr[1])
输出:
False
True