I am trying to return the two smallest values for a numeric list as a tuple. However the next code keeps returning first two values of a list.
def test():
list = [4, 5, 1, 9, -2, 0, 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()
Console output:
4,5
Is there any way to do this by iterating?
The variables min1
and min2
don't update, they are not references to the first and second element of the list, they are references to the values that were at indexes 0 and 1 when the assignment takes place. That you later change list[0]
and list[1]
doesn't matter.
In Python, both list indexes and variables are just references to the actual objects. Think of Python objects like balloons, and variables and indices are just labels tied to the a string attached to the balloon. You can attach multiple labels to the balloons, but if you than move the label to a different balloon, the other labels tied to the old balloon don't follow along.
Here, min1
and min2
were tied to balloons that already had the 0
and 1
index labels tied to them. Later on, when you assign to list[i]
, you retied a specific index label to another balloon, but the min1
and min2
labels didn't change.
As a side note, this part of your code has a rather obvious error:
if list[0] < list[1]:
list[i] = list[1]
else:
list[i] = list[1]
Both branches do the exact same thing, assign list[1]
to list[i]
.
You are otherwise doing completely incorrect assignments even if you hoped that changing list[0]
and list[1]
inside the loop would make a change to the values of min1
and min2
, you are changing list[i]
, the other value in the list, the one that's supposed to be smaller.
So for i = 2
, list[i]
is list[2]
and list[2] < list[0]
is true (1 < 4), you then test if list[0] < list[1]
(also true, 4 < 5), so you do list[i] = list[1]
, setting list[2] = 5
, leaving list[0]
set to 4
, list[1]
set to 5
, and in effect throwing away the 1
value that was present at list[2]
before.
Rather than compare with list[0]
or list[1]
, have your loop update min1
and min2
:
# 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]
I also made sure that min1 < min2
at the start, that makes the loop a lot simpler because if list[i] < min1
is not true then it can perhaps be smaller than min2
but you don't need to test against min1
a second time.
Note that we assign the list[i]
values to min1
and min2
here, you want to update those two variables with the value you just tested, provided list[i]
is indeed smaller than what you had before.