【问题标题】:How to change only the diagonal elements of a 2D list?如何仅更改 2D 列表的对角线元素?
【发布时间】:2021-06-10 01:45:09
【问题描述】:

所以我尝试创建一个 NxN 2D 数组,然后将其对角元素更改为 1。这是我的代码:

arr=[1,1,1,2,2,2]
table=[[0]*len(arr)]*len(arr)
for i in range(0,len(arr)):
    table[i][i]=1
print(table)

但是,每当我运行此代码时,我都会得到以下输出:

[[1, 1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1, 1]]

我希望得到这个:

[[1, 0, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0],
 [0, 0, 0, 1, 0, 0],
 [0, 0, 0, 0, 1, 0],
 [0, 0, 0, 0, 0, 1]]

我已经盯着我的代码看了好几个小时,但我不知道出了什么问题

【问题讨论】:

    标签: python-3.x list multidimensional-array


    【解决方案1】:

    您的二维“数组”包含 6 个相同的列表。对这些列表中的任何一个的更改也将反映在其他列表中。考虑一下:

    >>> l = [0] * 6
    >>> x = [l]
    >>> l[0] = 1
    >>> l
    [1, 0, 0, 0, 0, 0]
    >>> x
    [[1, 0, 0, 0, 0, 0]]
    >>> x = [l, l, l]
    >>> x
    [[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]]
    >>> x[-1][-1] = 100
    >>> x
    [[1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100]]
    

    这是因为x 列表包含l 列表,因此l 的任何更改也可以通过x 中对同一列表的引用看到。

    问题是在可变对象相乘时,因为它创建了多个对同一个可变对象的引用

    你应该像这样初始化你的表:

    table = [[0 for j in range(len(arr))] for i in range(len(arr))]
    

    table = [[0] * len(arr) for i in range(len(arr))]
    

    尽管使用了乘法,但它仍然有效,因为每个列表都不同。

    【讨论】:

    • 所以如果我初始化一个像 [0]*len(arr) 这样的数组并更改任何一个元素,它会更改所有元素吗?
    • @fahadhub:不是那种情况。我在答案中添加了一些解释。问题是对象相乘会为它们创建多个引用,而不是对象的新实例。在 [0]*6 的情况下,您会得到一个列表,其中包含对同一 0 对象的 6 个引用,但是,由于整数是不可变的(无法更改),当您更改其中一个时,您最终会得到一个 对象。但是列表是可变的,因此当您更改其中一个元素时不会获得新的列表对象,因此更改通过对列表的所有引用可见。
    【解决方案2】:

    有趣的是,您实际上只编辑了for 循环中的一个 列表,但只有五个指向该列表的指针。 (在这种情况下,列表将是[0, 0, 0, 0, 0, 0]。)您可以通过使用id() 打印table 中每个列表的ID 来看到这一点:

    >>> for t in table:
            print(id(t))
    
    2236544254464
    2236544254464
    2236544254464
    2236544254464
    2236544254464
    2236544254464
    

    您的号码可能与我的不同,但它们都是相同的号码,尽管如此。您还可以通过在每个索引分配语句之后放置print(table) 语句来看到对一个列表的编辑应用于table 中的其他列表。

    所以为了“解决”这个问题,我建议改用列表推导。例如:

    table = [[0]*len(arr) for _ in range(len(arr))]
    

    如果您检查每个列表的 id:

    >>> for t in table:
        print(id(t))
    
        
    2236544617664
    2236544616064
    2236544616320
    2236544615872
    2236544618368
    2236544622720
    

    由于它们不同,您现在可以使用仅更改对角线的方法:

    >>> for i in range(0,len(arr)):
            table[i][i]=1
    
    >>> table
    [[1, 0, 0, 0, 0, 0],
     [0, 1, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 0],
     [0, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 1, 0],
     [0, 0, 0, 0, 0, 1]]
    

    【讨论】:

      【解决方案3】:

      您可以创建表格并在嵌套循环中同时填充它:

      arr=[1,1,1,2,2,2]
      
      table = []
      for i in range(len(arr)):
          table.append([0]*len(arr))
          for j in range(len(arr)):
              if i == j:
                  table[i][j] = 1
      
      print(table)
      #[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
      

      【讨论】:

        【解决方案4】:

        有趣。 尝试使用 numpy 避免列表陷阱:

        import numpy as np
        org_row = [0]*5
        l = [org_row]*5
        x = np.array(l, np.int32)
        for i in range(len(x)):
            x[i][i]=1
        print(x)
        
        

        输出>:

        output>
        [[1 0 0 0 0]
        [0 1 0 0 0]
        [0 0 1 0 0]
        [0 0 0 1 0]
        [0 0 0 0 1]]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-12-17
          • 1970-01-01
          • 2019-08-18
          • 2019-05-10
          • 2020-02-27
          • 1970-01-01
          • 2021-11-16
          • 1970-01-01
          相关资源
          最近更新 更多