【问题标题】:Cell assignment of a 2-dimensional Matrix in Python, without numpyPython中二维矩阵的单元格分配,没有numpy
【发布时间】:2012-10-11 06:27:22
【问题描述】:

下面是我的脚本,它基本上创建了一个 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]

【问题讨论】:

  • 谢谢大家!我得到了它。我正在做的是制作一个相同列表的列表,这些列表都是指向同一个列表的指针。还要感谢你用 python 编写的正确方法。我是使用 python 的新手(4 周)。谢谢大家!

标签: python matrix variable-assignment


【解决方案1】:

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

我会这样做:

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 之类的内容。一般来说,要避免混合大小写的名称,而骆驼通常用于类名。请参阅PEP 8 -- Style Guide for Python Code 了解更多信息。

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

这是list comprehension

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

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

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

【讨论】:

    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

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

      list_AlignMatrix.append(list(list_AlignMatrixRow))
      

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

      【讨论】:

        【解决方案4】:

        要生成这样的矩阵,在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    
        

        【讨论】:

        • 谁能告诉我为什么我的回答投了反对票!!我认为它只是给出了他想要的结果
        • 您还应该简要说明为什么需要这样做(请参阅其他答案)。附言不是我的反对票。
        • 我不反对,但我认为有人这样做的原因很清楚:OP 试图 避免 让每个矩阵行都是相同的行。请参阅他的注释“这是发生的输出,但我不想要”。你重用了list_MatrixRow,这会让你陷入与OP遇到的同样的问题。
        • 我投了反对票,但由于我现在有一个竞争答案,所以我删除了反对票。我投了反对票,因为 OP 想要“单元格 [2][0] 上只有一个 5”。您将五个放在所有行上。否决票的第二个原因是这个非惯用位(i==0 and 5 or 0)。习惯上,它是5 if i == 0 else 0
        • deepcopy 会这样做,但它很慢,需要导入,并且比 matrixrow[:]list(matrixrow) 长得多。我承认它可以处理那些不能处理的嵌套情况,但是这里需要的副本很浅。
        猜你喜欢
        • 2019-08-30
        • 1970-01-01
        • 1970-01-01
        • 2011-02-28
        • 1970-01-01
        • 2014-08-04
        • 2015-05-23
        • 1970-01-01
        • 2011-12-02
        相关资源
        最近更新 更多