【问题标题】:In-place modification of Python lists就地修改 Python 列表
【发布时间】:2021-03-13 18:41:54
【问题描述】:

我正在尝试在主列表级别上对列表列表进行就地修改。但是,当我尝试修改迭代变量(下例中的row)时,它似乎创建了一个指向它的新指针,而不是修改它。


我的问题的最小示例。

c = [1,2,3]
for x in c:
    x = x + 3
print(c) #returns [1,2,3], expected [4,5,6]

上面的例子是我的问题的一个简单例子。有没有办法修改x elementwise,就地并让更改出现在 C 中?


我的问题的不那么琐碎的例子。我将所有 0 转换为 1,反之亦然。

A =  [[1,1,0],
      [1,0,1],
      [0,0,0]]
for row in A:
    row = list(map(lambda val: 1 - val, row))
print(A)

预期

A = [[0,0,1],
     [0,1,0],
     [1,1,1]]

返回

A = [[1,1,0],
     [1,0,1],
     [0,0,0]]

更新: 到目前为止很好的答案。我对迭代变量(第二个示例中的row)如何链接到可迭代变量(第二个示例中的A)感兴趣。

如果我执行以下操作,反转 A 的每个子列表,它会完美运行。

为什么下面的例子,我修改了迭代变量,但上面的例子没有?

A =  [[1,1,0],
  [1,0,1],
  [0,0,0]]

for row in A:
    row.reverse()
print(A)

#returns, as expected
A = [[0, 1, 1],
     [1, 0, 1], 
     [0, 0, 0]]

【问题讨论】:

  • 我已经更新了我的答案。

标签: python list in-place


【解决方案1】:

我在文档中找到了这个:https://docs.python.org/3/tutorial/controlflow.html#for

Python 的 for 语句迭代任何序列的项目(列表 或字符串),按照它们在序列中出现的顺序。

如果您需要在内部修改您正在迭代的序列 循环(例如复制所选项目),建议 你先复制一份。迭代一个序列不会 隐式复制。

我的第一个响应是错误的,当迭代一个列表时,它会返回该列表中的实际项目。但是,似乎它们在迭代时无法直接编辑。这就是为什么遍历整数列表的长度是有效的。

至于.reverse() 函数为什么起作用,我认为是因为它影响的是列表而不是值。我尝试在非列表数据类型上使用类似的内置函数,如字符串上的.replace(),但没有效果。

我尝试过的所有其他列表函数都有效:.append()、.remove() 和 .reverse(),正如您所展示的。我不知道为什么会这样,但我希望它能更清楚地说明你可以在 for 循环中做什么。

回答下面的老问题:

您使用 for 循环的方式不会影响实际列表,只会影响遍历列表的临时变量。有几种方法可以解决此问题。您可以计算列表的长度并直接修改列表,而不是遍历每个元素。

c = [1,2,3]
for n in range(len(c)):
    c[n] += 3
print(c) 

您还可以使用enumerate() 函数来遍历计数器和列表项。

c = [1,2,3]
for n, x in enumerate(c):
    c[n] = x + 3
print(c) 

在这种情况下,n 是一个计数器,x 是列表中的项目。

最后,您可以使用列表推导式生成一个新列表,其中一行具有所需的差异。

c = [1, 2, 3]
d = [x + 3 for x in c]
print(d)

【讨论】:

  • 你也可以只做c[n] += 3
  • “但是,在迭代它们时,它们似乎无法直接编辑。”当然可以。只是在这种特殊情况下,列表包含 int 对象,它不公开任何 mutator 方法,即它们是不可变的。
【解决方案2】:

在 Python 中将值插入现有列表的常用方法是使用enumerate,它可以让您同时迭代索引和值——然后使用索引来操作列表:

c = [1,2,3]
for index, value in enumerate(c):
    c[index] = value + 3

对于您的第二个示例,您几乎可以执行相同的操作:

A =  [[1,1,0],
  [1,0,1],
  [0,0,0]]

for row in A:
    for index, val in row:
        row[index] = 0 if val > 0 else 1

在第二个示例中,A 中的列表对象成为循环变量 row - 因为您只是对它们进行变异(而不是分配给它们),所以您不需要 enumerate 和索引

【讨论】:

    【解决方案3】:

    如果你想在不创建额外变量的情况下保持简洁,你也可以这样做:

    c = [1,2,3] 
    print(id(c)) 
    c[:] = [i+3 for i in c] 
    print(c, id(c))
    

    输出:

    2881750110600
    2881750110600 [4, 5, 6]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-17
      • 2015-11-07
      • 2012-11-11
      • 2019-11-10
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多