7

下面是我的脚本,它基本上创建了一个 12x8 的零矩阵,用 0 填充。然后我要一个一个地填充它。因此,假设第 2 行第 0 行需要为 5。我该怎么做?下面的示例显示了我是如何做到的以及错误的(根据我的需要)输出:

list_MatrixRow = []
list_Matrix = [] #Not to be confused by what the book calls, optimal alignment score matrix

int_NumbOfColumns = 12
int_NumbOfRows = 8

for i in range (0, int_NumbOfColumns): # Puts Zeros across the first Row
    list_AlignMatrixRow.append(0)
for i in range (0, int_NumbOfRows):
    list_AlignMatrix.append(list_AlignMatrixRow) 
#add the list in another list to make matrix of Zeros
#-------------------THE ACTUAL PROBLEMATIC PART; ABOVE IS FINE(It Works)------------

list_AlignMatrix[2][0] = 5 
# This is what logically makes sense but here is the output 
# which happens but I don't want (there should be all 0s and 
# only one 5 on the cell [2][0]):

[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4

4 回答 4

10

每行都指向同一个子列表。这是重复附加相同子列表的结果。因此,当您修改一行时,您最终会修改其他行。

我会这样做:

ncols = 12
nrows = 8
matrix = [[0] * ncols for i in range(nrows)]
matrix[2][0] = 5 

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],
 [5, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

关于编码风格的旁白:在 Python 中将对象的类型包含在其名称中是一种糟糕的形式。我选择重命名int_NumbOfColumnsncols. 如果您需要更具描述性的内容,请使用column_count. 一般来说,要避免混合大小写的名称,而骆驼通常用于类名。有关更多信息,请参阅PEP 8 -- Python 代码样式指南

编辑:既然你提到你是 Python 新手,这里有一点解释。

这是一个列表理解

matrix = [[0] * ncols for i in range(nrows)]

它也可以写成一个普通的for循环:

matrix = []
for i in range(nrows):
    matrix.append([0] * ncols)
于 2012-10-21T03:31:08.763 回答
5

中的每个条目都是对同一对象list_AlignMatrix的引用。您需要为矩阵中的每一行创建一个新实例。这是正在发生的事情的说明:list

>>> l = [0]
>>> l2 = [l,l,l]
>>> l2
[[0], [0], [0]]
>>> l2[0][0] = 1
>>> l2
[[1], [1], [1]]

您可以使用该id()函数来确认每个条目l2是对同一对象的引用:

>>> [id(x) for x in l2]
[161738316, 161738316, 161738316]

要制作行列表的新副本,您可以像这样重写第二个循环:

for i in range (0, int_NumbOfRows):
    list_AlignMatrix.append(list(list_AlignMatrixRow)) 

构造list函数将创建 的副本list_AlignMatrixRow,如下例所示:

>>> l = range(10)
>>> l2 = list(l)
>>> l == l2
True
>>> l is l2
False
于 2012-10-21T03:21:34.100 回答
1

当您 appendlist_AlignMatrixRow时,它只是附加对原始列表的引用,因此实际上只有一个一维列表,并且矩阵的每一行都指向它。要创建一个新列表,您需要实际创建一个新列表:

list_AlignMatrix.append(list(list_AlignMatrixRow))

注意对 list 的调用,它通过迭代和复制 list_AlignMatrixRow 的元素来创建一个列表

于 2012-10-21T03:23:01.227 回答
1

要生成这样的矩阵,在 python 中,如果你想生成一个全为 0 的行,你应该使用这样的列表计算,

>>> import copy
>>> list_MatrixRow=[0 for i in range(12)]
>>> list_MatrixRow
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

ce 然后您可以以相同的方式创建列表列表

list_Matrix=[[0 for j in range(12)] for i in range(8)]

现在您可以编辑任何元素

>>> list_Matrix[0][2]=12345
>>> list_Matrix[0][2]
12345
>>> list_Matrix
[[0, 0, 12345, 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, 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, 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, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

如果你想创建包含所有第 5 列的矩阵,你可以在列表理解上使用短路评估

>>> list_MatrixRow=[(i==0 and 5 or 0) for i in range(12)]
>>> list_MatrixRow
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> list_Matrix=[list_MatrixRow for i in range(8)]
>>> list_MatrixRow
[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> list_Matrix
[[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
>>> list_Matrix[0][0]
5    
于 2012-10-21T03:23:57.070 回答