9

if arr = [4,3,2,1] and i want to swap the first value with the minimum of the array , if am using this on python

arr[0] , arr[arr.index(min(arr))] = min(arr) , arr[0] 
#or   
arr[0] , arr[arr.index(min(arr))] = arr[arr.index(min(arr))] , arr[0]

they are not working but if i do this

b = arr.index(min(arr))  
#and then  
arr[0] , arr[b] = arr[b] , arr[0]

this works fine. Can anyone explain why ?

7
  • 1
    Python evaluates expressions left-to-right Commented Aug 16, 2018 at 20:54
  • @smci: Except that it's not actually left-to-right here. It could have been designed to be left-to-right, but it wasn't. (I really wish Python multiple assignment had been designed to evaluate all expressions left-to-right, then start assigning things.) Commented Aug 16, 2018 at 21:31
  • @user2357112: then please explain what it is. It is parsed left-to-right, then each expression is dynamically evaluated, yes? For a tuple assignment L1, L2 = R1, R2, L1 is evaluated first, then R1, then L2, then R2? Commented Aug 16, 2018 at 22:07
  • @smci: Nope. R1, R2, L1, (first assignment happens here), L2, (second assignment happens here). Commented Aug 16, 2018 at 22:09
  • 1
    @smci: The older answer mentions the exception for assignments, but in a way that's easy to miss. I've edited it to be a bit more clear. Commented Aug 16, 2018 at 22:22

1 Answer 1

8

It has to do with the order of the operations.

We can subclass lists to instrument them to show what they're doing.

class TracingList(list):
    def __getitem__(self, key):
        value = super().__getitem__(key)
        print(self, "reading", key, "=", value)
        return value

    def __setitem__(self, key, value):
        print(self, "writing", key, "=", value)
        super().__setitem__(key, value)

    def index(self, value):
        index = super().index(value)
        print(self, "finding index of", value, "=", index)
        return index


arr = TracingList([4, 3, 2, 1])
arr[0], arr[arr.index(min(arr))] = min(arr), arr[0]
print(arr)
print("===")

arr = TracingList([4, 3, 2, 1])
arr[0], arr[arr.index(min(arr))] = arr[arr.index(min(arr))], arr[0]
print(arr)
print("===")

arr = TracingList([4, 3, 2, 1])
b = arr.index(min(arr))
arr[0], arr[b] = arr[b], arr[0]
print(arr)

prints out

[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] finding index of 1 = 0
[1, 3, 2, 1] writing 0 = 4
[4, 3, 2, 1]
===
[4, 3, 2, 1] finding index of 1 = 3
[4, 3, 2, 1] reading 3 = 1
[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] finding index of 1 = 0
[1, 3, 2, 1] writing 0 = 4
[4, 3, 2, 1]
===
[4, 3, 2, 1] finding index of 1 = 3
[4, 3, 2, 1] reading 3 = 1
[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] writing 3 = 4
[1, 3, 2, 4]
Sign up to request clarification or add additional context in comments.

To explain, arr[0] gets set before arr[arr.index(min(arr))] gets evaluated and set. Thus once arr[0] is set to 1, the index of the min becomes 0. So arr[arr.index(min(arr))] assigns 4 to index 0.
This means that if you change the order of the assignments, i.e. arr = [4,3,2,1]; arr[arr.index(min(arr))], arr[0] = arr[0], min(arr); print(arr), you get the "correct" result. :o
Ok but there's no explanation of what the order of evaluation actually is, or why it is so, or what principle is being followed. This is just like saying "The order is whatever it is, because it is so". Python evaluates expressions L-to-R, except for assignments, where the RHS is evaluated before the LHS

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.