无法使用 for 循环将二维列表中的元素替换为一维列表

Having trouble replacing elements in a 2d list with a 1d list using for-loops

我被要求用一维列表中的元素替换二维列表中的一些元素。规则是用 list2 替换 list1 的第一行。下一行中的元素将被前一行中的每个元素替换 3 次。因此第二行将包含 33、39、45 和 51,第三行将包含 99、117、135 和 153 ...一直到第 10 行。

这是我的代码:

list1 = [[0]*4]*10
list2 = [11,13,15,17]

list1[0] = list2

i = 1        
for i in range(9):
    j = 0
    for j in range(4):
        list1[i][j] = list2[j]*(3**i)
        j+=1
    i+=1

这段代码我得到的结果基本上只有第一行是正确的,但之后的其余行都是72171、85293、98415和111537(即3到8)。我不确定是哪个部分给我的错误。

以下是对您的代码的一些评论,以及如何使其按照问题所述执行操作的示例:

(1.) 引用与副本: list1 = [[0]*4]*10 创建一个 4 元素列表并用 10 个引用填充 list1(不是 10它的副本)。

有关这意味着什么的示例,请观看:

list1 = [[0]*4]*10
list1[1][0] = 33
list1[1][1] = 39
list1[1][2] = 45
list1[1][3] = 51
print(list1)

...给出这个:

[[33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51]]

换句话说,更新 list1 中的一个列表元素会更新所有元素,因为 list1 的每个元素都只是对同一列表的引用。

如果这不是您想要的,您可以使用 list1 = [[0]*4 for _ in range(10)] 来为 list1 中的每个索引提供一个不同的列表(总共 10 个):

list1 = [[0]*4 for _ in range(10)]
list1[1][0] = 33
list1[1][1] = 39
list1[1][2] = 45
list1[1][3] = 51
print(list1)

... 给出:

[[0, 0, 0, 0], [33, 39, 45, 51], [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]]

您编写的代码往往暗示需要采用上述第二种方法。

(2.) 假设嵌套列表无法替换的代码修复: 从问题中不清楚是否允许替换 list1 中的每个列表以获得所需的值,或者如果您希望保留嵌套列表并简单地修改它们的数字内容。

如果不允许列表替换,那么你的代码可以这样重写:

list1 = [[0]*4 for _ in range(10)]
list2 = [11,13,15,17]
list1[0][:] = list2

for i in range(9):
    for j in range(4):
        list1[i + 1][j] = list2[j]*(3**(i + 1))
print(list1)

...给予:

[[11, 13, 15, 17], [33, 39, 45, 51], [99, 117, 135, 153], [297, 351, 405, 459], [891, 1053, 1215, 1377], [2673, 3159, 3645, 4131], [8019, 9477, 10935, 12393], [24057, 28431, 32805, 37179], [72171, 85293, 98415, 111537], [216513, 255879, 295245, 334611]]

请注意,对您的代码进行了这些更改:

  • 更改了 list1 的初始化以分配 10 个不同的嵌套列表。
  • 消除了i = 1(不需要因为for循环负责初始化i),j = 0(类似原因),j+=1(不是需要因为 for 循环负责更新 j) 和 i+=1(类似的原因)。
  • 已将 list1[i][j] 更改为 list1[i + 1][j] 以修复索引。
  • 已将 3**i 更改为 3**(i + 1) 以计算正确的乘数。

(3.)假设嵌套列表可以被替换的代码修复:在这种情况下,你的循环逻辑可以被简化并且你不需要在初始化时使用嵌套列表list1.

这是一个 long-hand 方法来完成您的要求,它将用具有所需值的新嵌套列表覆盖 list1 的内容:

list1 = [None] * 10
list2 = [11,13,15,17]
list1[0] = list2
mul = 3
for i in range(1, len(list1)):
    temp = [0] * len(list2)
    for j in range(len(list2)):
        temp[j] = mul * list2[j]
    list1[i] = temp
    mul *= 3
print(list1)

这是一种在循环中使用列表理解的方法:

list1 = [None] * 10
list2 = [11,13,15,17]
list1[0] = list2
mul = 3
for i in range(1, len(list1)):
    list1[i] = [mul * v for v in list2]
    mul *= 3
print(list1)

最后,这是一个非常紧凑的嵌套列表理解方法:

list1 = [None] * 10
list2 = [11,13,15,17]
list1 = [[(3 ** i) * v for v in list2] for i in range(len(list1))]

发生这种情况的原因是您正在处理 list1 的 0 个元素的副本,因此每当您进一步修改时,所有内容都将替换为新值,它不是引用中相同对象的副本。

 for i in range(9):
     tmp = []
     for j in range(4):
         tmp.append(list2[j]*(3**i))
     list1[i] = tmp

这就是您所需要的

您可以使用 numpy 数组使这更容易:

import numpy as np 
list1 = np.zeros((10,4), dtype=int)
list1[0] = [11,13,15,17]

for i in range(1,10):
    list1[i] = 3*list1[i-1]