Python中2维矩阵的单元格分配(不使用numpy)

7
下面是我的脚本,它基本上创建了一个12x8的零矩阵,然后我想逐个填充它。比如说第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]

谢谢大家!我明白了。我做的是将指向同一列表的指针列表制作成一个列表。同时,感谢您提供正确的Python编写方式。我是新手(4周)使用Python。谢谢大家! - StudentOfScience
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_NumbOfColumns重命名为ncols。如果你需要更多描述性的名称,请使用像column_count这样的名称。通常应避免使用mixedCase名称,而CamelCase通常用于类名称。有关更多信息,请参见PEP 8 -- Python代码风格指南

Edit: 由于您提到您是Python新手,这里有更详细的解释。

这是一个列表推导式

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

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

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

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

1
当您附加list_AlignMatrixRow时,它只是附加到原始列表的引用,因此实际上只有一个一维列表,您矩阵的每一行都指向它。要创建新列表,您需要实际创建新列表:
list_AlignMatrix.append(list(list_AlignMatrixRow))

请注意调用list的操作,它通过迭代list_AlignMatrixRow的元素并复制它们来创建一个列表。

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]

首先,您可以以同样的方式创建列表的列表

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    

有人能告诉我为什么我的回答会被负评吗?我认为它只是给出了他想要的结果。 - dileep nandanam
1
我不会点踩,但我认为有人这样做是很清楚的:原帖作者试图避免每个矩阵行都成为相同的行。请看他的注释“这是发生的输出,但我不想要”。您重复使用了list_MatrixRow,这将使您陷入与原帖作者相同的问题。 - DSM
2
deepcopy可以实现,但它速度较慢,需要导入,并且比matrixrow[:]list(matrixrow)要长得多。我承认它可以处理那些不行的嵌套情况,但在这里所需的复制是浅层的。 - DSM
对于基本类型的矩阵,深拷贝并不高效。但是在处理更高级对象时,它更可取。 - dileep nandanam
在这种情况下,“deepcopy”并不常用。只需要浅复制即可。当我们谈论整数列表时,最常见的复制方式是使用列表构造函数或切片。 - Steven Rumbalski
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接