【问题标题】:Why this while loop does not work?为什么这个while循环不起作用?
【发布时间】:2017-07-11 13:20:46
【问题描述】:

谢谢大家!我改了代码,还是报错:

列表索引超出范围。

为什么?

M  = []
B = [1, 3, 5]
C = [2, 4, 6]
while (B and C):
    if B[0] <= C[0]: 
        M.append(B.pop(0))
    if C[0] <= B[0]: 
        M.append(C.pop(0))

print('Updated list: ', M)

`

【问题讨论】:

  • 您是否使用调试器或打印语句单步执行?
  • 是的,它只是一直在运行......
  • 调试告诉你什么?它的运行是有原因的,调试会告诉你你需要知道的一切。
  • 您期望“B 和 C”返回什么?使用交互式提示,这将返回 C 的非零内容,并导致条件不评估为 False。
  • 调试没有告诉我任何事情。继续跑。当我后来检查它时,它显示“停止运行”。就是这样。

标签: python python-3.x while-loop


【解决方案1】:

你可以通过打印来调试,观察代码中发生了什么:

Before Popping: 
======================================
B and C:  [2, 4, 6]
B:  [1, 3, 5]
C:  [2, 4, 6]
======================================
Enters B[0] <= C[0] since 1 <= 2
B[0] = "1" is popped out

New value for B and C: 
B:  [3, 5]
C:  [2, 4, 6]

======================================
Enters C[0] <= B[0] since 2 <= 3
C[0] = "2" is popped out

New value for B and C: 
B:  [3, 5]
C:  [4, 6]

After Popping: 
*****************************************
B and C:  [4, 6]
B:  [3, 5]
C:  [4, 6]
*****************************************
Before Popping: 
======================================
B and C:  [4, 6]
B:  [3, 5]
C:  [4, 6]
======================================
Enters B[0] <= C[0] since 3 <= 4
B[0] = "3" is popped out

New value for B and C: 
B:  [5]
C:  [4, 6]

======================================
Enters C[0] <= B[0] since 4 <= 5
C[0] = "4" is popped out

New value for B and C: 
B:  [5]
C:  [6]

After Popping: 
*****************************************
B and C:  [6]
B:  [5]
C:  [6]
*****************************************
Before Popping: 
======================================
B and C:  [6]
B:  [5]
C:  [6]
======================================
Enters B[0] <= C[0] since 5 <= 6
B[0] = "5" is popped out

New value for B and C: 
B:  []
C:  [6]

======================================

最后得到IndexError: list index out of range,因为B[]

【讨论】:

    【解决方案2】:

    B 和 C 收敛到:

    B = [4, 5]
    C = [2, 3, 6]
    

    C[0](2) 显然不大于或等于B[0](4)

    所以你要弹出 B 的分支不再被击中,你就会陷入无限循环

    【讨论】:

    • 谢谢!我更改了代码,但它仍然无法正常工作:(
    【解决方案3】:

    在您的 while 循环中,您在 B 和 C 上使用 and 运算符。根据 Python 2.7 的参考 5.1,只有空数组会产生 False。

    https://docs.python.org/release/2.7.13/library/stdtypes.html#truth-value-testing

    正如 Mark 所建议的,在您第一次弹出之后,条件 B[0]

    【讨论】:

      【解决方案4】:

      出了什么问题: 在您执行B.pop(0) 之后的第三次while 循环列表B 变为空。因此,当您在列表B 已经为空时在下一行调用B[0] 时,您会收到错误IndexError: list index out of range

      用打印语句解释:

      我在你的代码中添加了一些打印语句

      M  = []
      B = [1, 3, 5]
      C = [2, 4, 6]
      while (B and C):
          print("==============")
          if B[0] <= C[0]: 
              M.append(B.pop(0))
          print("B: " + str(B))
          if C[0] <= B[0]: 
              M.append(C.pop(0))
          print("C: " + str(C))
      

      我得到的结果是:

      ==============
      B: [3, 5]
      C: [4, 6]
      ==============
      B: [5]
      C: [6]
      ==============
      B: []
      Traceback (most recent call last):
        File "python", line 9, in <module>
      IndexError: list index out of range
      

      查看B 何时为空,您无法调用B[0]。当您尝试使用list[x] 从列表中获取元素时。 x 必须介于 0 和列表大小 - 1 之间。

      建议: 我强烈建议您学习如何使用print to debug your code。这是非常有用的。尤其是在 Python 这样的过程语言中。

      【讨论】:

      • 没问题,我很乐意提供帮助。我希望这可以帮助您更好地了解您的代码出了什么问题。欢迎来到 StackOverflow。如果您发现任何其他有用的答案并解决了您的问题,请将其标记为解决方案。这样,它将帮助社区和将来遇到与您相同的问题的程序员同行。干杯
      【解决方案5】:

      因为最终您会在代码中的某个点结束您的列表之一为空 - 所以它没有 索引 0 来引用。具体来说,列表 B 中的 5 是该列表“已使用”的最后一个元素 - 复制到 M 并从 B 中删除,之后列表没有索引 0。

      我看到了两种解决方法:

      下面的第一个解决方案解决了您的问题,在这种情况下,您不会在 while 循环开始时存在 BC 来触发 B and C 以返回 False 并破坏您最终,在B[0] &lt;= C[0] 中,B 中的 5 被删除,代码移动到 C[0] &lt;= B[0] 旁边,因此出错,因为 B 为空。代码的功能相同,如果B[0] &lt;= C[0] 那部分代码运行,如果不是(在这种情况下C[0] &lt;= B[0] 为真)执行原始第二个if 语句中的代码,而不测试该条件。

      这意味着while 循环运行更多次,因为它每个循环只执行一次操作,但这意味着它在每次更改列表后测试while (B and C),从而避免尝试对空列表执行操作索引,因为 BC 如果它们为空,则计算结果为 false,并且 while 循环将退出。

      M = []
      B = [1, 3, 5]
      C = [2, 4, 6]
      while (B and C):
          if B[0] <= C[0]:
              M.append(B.pop(0))
          else:
              M.append(C.pop(0))
      
      print('Updated list: ', M)
      

      我提出的第二个解决方案(我首先提出的,虽然更明确,但不那么简单)是明确指定 BC 都需要在其中包含某些内容(即必须在运行原始代码中的每个 if 语句之前有一个索引 0),如果其中一个为空,则在抛出错误的 if 语句可以运行之前跳出 while 循环:

      M = []
      B = [1, 3, 5]
      C = [2, 4, 6]
      
      while (B and C):
          if len(B) == 0 or len(C) == 0:
              break
          if B[0] <= C[0]:
              M.append(B.pop(0))
          if len(B) == 0 or len(C) == 0:
              break
          if C[0] <= B[0]:
              M.append(C.pop(0))
      
      print('Updated list: ', M)
      

      无论哪种情况,您都可以在 while 循环之后和 print 函数之前添加此代码,以确保将所有列表项添加到 M

      D = B+C
      M.append(D.pop(0))
      

      基本上,这只是将空列表添加到带有一个项目的列表中,新列表 D 在索引 0 处有一个项目,然后将其附加到 M

      【讨论】:

      • 对 B 和 C 的 len 测试对于 while 条件来说是多余的。
      • 为什么?我做了什么解决了这个问题?
      • 循环中的第一个测试与 while 条件是多余的。正是您添加的第二个测试使事情变得更好。而if len(B) == 0可以更简单的写成if not B
      【解决方案6】:

      将您的第二个if 更改为elif

      【讨论】:

      • 不清楚这是必需的输出。 OP 只是询问列表索引问题和无限循环,这两个问题都已修复。
      猜你喜欢
      • 1970-01-01
      • 2016-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 2015-11-16
      相关资源
      最近更新 更多