我在编写一个用于处理多维矩阵的Matrix类的setter函数时遇到了麻烦,因为我实现了动态编程算法。
使用嵌套列表存储矩阵。由于维度未知,因此代码背后的想法是使用坐标(索引列表)并在从坐标读取索引时迭代地进入矩阵。
def setField(self, coordinate, value):
coordinate = coordinate[::-1] # reverse the coordinate so .pop() can be used
field = self.matrix
while len(coordinate) > 1:
field = field[coordinate.pop()]
field[coordinate[0]] = value
使用代码:
>>> m = Matrix([3,3,3]) # initialize Matrix of size 3 in all dimensions
>>> m.tolist() # list representation
[[[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]]]
>>> m.setField([1,1,1], 42) # at position [1,1,1] insert 42
>>> m.tolist()
[[[0, 0, 42], [0, 0, 42], [0, 0, 42]], [[0, 0, 42], [0, 0, 42], [0, 0, 42]], [[0, 0, 42], [0, 0, 42], [0, 0, 42]]]
现在麻烦的是,进入矩阵'部分是通过参考矩阵完成的。由于我不明白的原因,变化不仅发生在一个领域(矩阵应该被改变为给定值),而是发生在矩阵表示的每个子列表中。
让我更加困惑的是,以下代码在Python shell中运行得很好:
>>> m = [[0,0],[0,0]]
>>> field = m
>>> field = field[0]
>>> field[1] = 1
>>> m
[[0, 1], [0, 0]]
编辑/解释
正如答案所指出的,矩阵中的所有子列表实际上都是相同的。
>>> m = Matrix([2,2])
>>> id(m.matrix[0]) == id(m.matrix[1])
True
要避免此行为,必须使用副本。
答案 0 :(得分:0)
您所看到的问题是因为矩阵的子数组在内存中实际上是相同的,所以修改它们会改变它们。
这就是你正在做的事情:
>>> a = [0, 0]
>>> m = [a, a]
>>> m
[[0, 0], [0, 0]]
>>> m[0][1] = 42
>>> m
[[0, 42], [0, 42]]
>>> id(m[0]) == id(m[1]) # same object in memory
True
这是你想要做的:
>>> a = [0,0]
>>> m = [a.copy(), a.copy()]
>>> m[0][1] = 42
>>> m
[[0, 42], [0, 0]]
>>> id(m[0]) == id(m[1]) # different objects in memory
False
话虽如此,在numpy中做起来容易得多:
>>> import numpy as np
>>> m = np.zeros((2, 2))
>>> m[0,1] = 42
>>> m
array([[ 0., 42.],
[ 0., 0.]])