【问题标题】:Assinging a new value to item in list during for loop doesnt work?在 for 循环期间为列表中的项目分配新值不起作用?
【发布时间】:2021-11-18 00:32:31
【问题描述】:

我有一个物品清单。在 for 循环中,我检查项目是否为 3。如果是 3,则应将 3 更改为 2。这是我想到使用 for 循环的两种方式。但只有最后一个有效。

有没有一种方法可以让第一个 for 循环工作而不会失去其“pythonic”风格?

a = [1, 2, 3]

for num in a:
    if num == 3:
        num = 2
# -> [1, 2, 3]



for i in range(len(a)):
    if a[i] == 3:
        a[i] = 2
# -> [1, 2, 2]

【问题讨论】:

  • pythonic 的解决方案不是就地修改列表,而是使用更新的值创建列表的新副本。
  • 您必须做出基本的设计决策。您要就地修改列表还是创建副本?
  • 你的第二个 sn-p 绝对是一个合理的,如果不是完美的解决方案。

标签: python list loops for-loop variable-assignment


【解决方案1】:

没有办法分配一个裸名 (num) 并让它影响一个容器 (列表 a)。您需要使用索引。虽然,使用enumerate 更加Pythonic:

for i, num in enumerate(a):
    if num == 3:
        a[i] = 2

另一种选择是使用完整切片赋值从生成器表达式中完全覆盖列表的内容:

a[:] = (2 if num==3 else num for num in a)

【讨论】:

  • 哇,不知道enumerate 存在,非常有帮助,谢谢
  • 使用生成器推导的完整切片分配可以被简单的列表推导替换(这在内存和速度方面更有效):a = [2 if num == 3 else num for num in a]
【解决方案2】:

让我们看看这段代码:

for i in [1, 2, 3]:
    ...

在 for 循环中,[1, 2, 3] 是一个列表对象。 i 只是一个保存指针的变量(基本上是对数据的引用)。当您在循环中执行i = 3 之类的操作时,变量i 被设置为保存数字3,但实际列表没有改变。列表推导可用于您想要完成的任务:

a = [1, 2, 3]
l = [2 if num == 3 else num for num in a]
# note that this is a ternary operator in a list comprehension

如果您希望使用for 循环,那么带有索引分配的enumerate 方法就可以解决问题:

a = [1, 2, 3]
for i, num in enumerate(a):
    if num == 3:
        a[i] = 2

您也可以像这样手动操作:

i = 0
for num in a:
    if num == 3:
        num[i] = 2
    i += 1

请注意:

  • 列表理解创建一个新列表(并且不编辑旧列表)
  • 我上面展示的枚举方法确实编辑了原始列表(但可能会更慢,不过这取决于你的机器)
  • 我提出的最后一个选项只是为了说明enumerate 方法的作用并表明它是一个选项

【讨论】:

  • 为什么要手动操作?
【解决方案3】:

要就地修改,这可能更符合 Python 风格:

for i, n in enumerate(a):
    if n == 3:
        a[i] = 2

如果您对如何替换项目进行冗长的测试,这也可能更可取,这样列表理解可能会很笨拙。

【讨论】:

    【解决方案4】:

    尝试列表理解:

    >>> a = [1, 2, 3]
    >>> a = [2 if num == 3 else num for num in a]
    >>> a
    [1, 2, 2]
    

    【讨论】:

      【解决方案5】:

      如果不是列表理解,您可以使用枚举:

      a = [1,2,3]
      for count, num in enumerate(a):
          if num == 3:
              a[count] = 2
      

      地图也可以(真的只是使用列表推导式),但它有点不那么 Python (对某些人来说,lambda 也很困惑):

      a = [1,2,3]
      a = list(map(lambda num: 2 if num==3 else num, a))
      

      您可以做的另一件事是,如果您正在迭代的变量是某个具有包含副作用的方法的对象(例如 setter),您可以就地使用它。例如,假设我有一些从int 继承的myInteger 类,其方法可以让我设置一些值。假设它是这样的:

      myInt = myInteger(5)
      print(myInt.value)
      >> 5
      
      myInt.set_value(6)
      print(myInt.value)
      >>6
      

      这将为您提供您正在寻找的界面:

      for num in a:
          if num == 3:
              a.set_value(2)
      

      权衡是您正在编写一个奇怪的类来执行此操作,这将在未来导致混乱。

      【讨论】:

      • list(map(lambda)) 比它需要的深两层。真的,只需使用理解即可。
      • 是的,列表推导是去那里的方式。但至少这是一种选择!
      猜你喜欢
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      相关资源
      最近更新 更多