2017-08-11 36 views
0

我在为应用多维矩阵的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外壳:

>>> m = [[0,0],[0,0]] 
>>> field = m 
>>> field = field[0] 
>>> field[1] = 1 
>>> m 
[[0, 1], [0, 0]] 
  • 我在做什么错在这里?
  • 为什么Python的行为如此?

编辑/解释

正如指出作为一个答案,在矩阵中的所有子表实际上是相同的。

>>> m = Matrix([2,2]) 
>>> id(m.matrix[0]) == id(m.matrix[1]) 
True 

要避免此行为,必须使用副本。

+0

我不明白是什么问题。另外,不仅*矩阵中的一个期望的字段发生了变化*意味着什么? – wallyk

+0

有什么理由不使用numpy吗?没有理由重新发明轮子 – user3080953

+0

@ user3080953我将使用该类来表示评分矩阵,并且性能不是问题。然而,它需要覆盖一些不同的初始化,所以我认为最好把它们包装在一个类中。 – jules

回答

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.]]) 
+0

谢谢你的回答!我猜测它是这样的,但是当它在shell中工作时我感到非常困惑。 – jules