在列表中找到两个最小值

问题描述

我试图返回一个数字列表的两个最小值作为元组。 但是,下一个代码将继续返回列表的前两个值。

def test(): 
  list = [4,5,1,9,-2,3,-5] 
  min1 = list[0]
  min2 = list[1]

  length = len(list)
  
  for i in range(1,length):
    if list[i] < list[0]:
        if list[0] < list[1]:
            list[i] = list[1]
        else:
            list[i] = list[1] 
    else:
        if list[i] < list[1]:
            list[i] = list[1]
    print(min1,min2)

    return (min1,min2) 

test()

控制台输出

4,5

有没有办法通过迭代来做到这一点?

解决方法

变量min1min2不会更新,它们不是对列表的第一个和第二个元素的引用,它们是对索引0和1处的值的引用任务何时发生。以后更改list[0]list[1]没关系。

在Python中,列表索引和变量都只是对实际对象的引用。想想像气球这样的Python对象,变量和索引只是与附加到气球上的字符串相关的标签。您可以在气球上附加多个标签,但是如果要将标签移动到另一个气球上,则与旧气球绑在一起的 other 标签不会随之出现。

在这里,min1min2被绑定到已经具有01索引标签的气球上。稍后,当您分配给list[i]时,您将特定的索引标签退休了另一个气球,但是min1min2标签没有改变。

请注意,代码的这一部分有一个相当明显的错误:

if list[0] < list[1]:
    list[i] = list[1]
else:
    list[i] = list[1] 

两个分支都做同样的事情,将list[1]分配给list[i]

否则,即使您希望在循环中更改list[0]list[1]也会更改min1min2的值,否则您所做的分配是完全错误的,您正在更改列表中的 other list[i],该值应该较小。

因此对于i = 2list[i]list[2],而list[2] < list[0]是真实的(1 list[0] < list[1]是否也是真实的(4 list[i] = list[1],设置list[2] = 5,将list[0]设置为4,将list[1]设置为5,并生效丢弃之前在1处出现的list[2]值。

让您的循环更新list[0]list[1]而不是与min1min2进行比较:

# min1 is always smaller than min2
min1,min2 = list[:2]
if min2 < min1:
    min1,min2 = min2,min1

for i in range(1,length):
    if list[i] < min1:
        min1 = list[i]
    elif list[i] < min2:  # but equal to or greater than min1!
        min2 = list[i]

我还确保开始时使用min1 < min2,这使循环变得更加简单,因为如果list[i] < min1不正确,则它可能可能小于{{ 1}},但您无需再次测试min2

请注意,我们在这里将min1的值分配给list[i]min1,您要使用刚刚测试的值更新这两个变量min2确实比以前小。