Не правильно работает код на сортировку списка

Код:

a = [78, -32, 5, 39, 58, -5, -63, 57, 72, 9, 53, -1, 63, -97, -21, -94, -47, 57, -8, 60, -23, -72, -22, -79, 90, 96, -41, -71, -48, 84, 89, -96, 41, -16, 94, -60, -64, -39, 60, -14, -62, -19, -3, 32, 98, 14, 43, 3, -56, 71, -71, -67, 80, 27, 92, 92, -64, 0, -77, 2, -26, 41, 3, -31, 48, 39, 20, -30, 35, 32, -58, 2, 63, 64, 66, 62, 82, -62, 9, -52, 35, -61, 87, 78, 93, -42, 87, -72, -10, -36, 61, -16, 59, 59, 22, -24, -67, 76, -94, 59]

n = len(a)

for i in range(n-1):
    
    a[i] , a[a.index(min(a[i:]))] = a[a.index(min(a[i:]))] , a[i]

print(*a)

Вывод:

78 -32 5 39 58 -5 -63 57 72 9 53 -1 63 -97 -21 41 -47 57 -8 60 -23 -72 -22 -79 90 96 -41 -71 -48 84 89 -96 -16 94 -60 -64 -39 60 -14 -62 -19 -3 32 98 14 43 3 -56 71 -71 -67 80 27 92 92 -64 0 -77 2 -26 41 3 -31 48 39 20 -30 35 32 -58 2 63 64 66 62 82 -62 9 -52 35 -61 87 78 93 -42 87 -72 -10 -36 61 -16 59 59 22 -24 -67 76 -94 -94 59

Как исправить, что бы сортировка работала корректно?


Ответы (2 шт):

Автор решения: Stanislav Volodarskiy

Добавляю отладочную печать в ваш код:

def index(a, i):
    j = a.index(min(a[i:]))
    print('j', j)
    return j

a = [78, -32, 5, 39, 58, -5, -63, 57, 72, 9, 53, -1, 63, -97, -21, -94, -47, 57, -8, 60, -23, -72, -22, -79, 90, 96, -41, -71, -48, 84, 89, -96, 41, -16, 94, -60, -64, -39, 60, -14, -62, -19, -3, 32, 98, 14, 43, 3, -56, 71, -71, -67, 80, 27, 92, 92, -64, 0, -77, 2, -26, 41, 3, -31, 48, 39, 20, -30, 35, 32, -58, 2, 63, 64, 66, 62, 82, -62, 9, -52, 35, -61, 87, 78, 93, -42, 87, -72, -10, -36, 61, -16, 59, 59, 22, -24, -67, 76, -94, 59]

n = len(a)

for i in range(n-1):
    print('-')
    print('i', i)
    
    a[i] , a[index(a, i)] = a[index(a, i)] , a[i]

print(*a)

И получаю что значение j меняется во время присваивания:

$ python sort.py 
-
i 0
j 13
j 0
-
...

То есть перестановка элементов их не переставляет, а портит массив. Потому что оператор множественного присвоения компилируется так:

     # a[i] , a[a.index(min(a[i:]))] = a[a.index(min(a[i:]))] , a[i]
 
     # выражения справа сохраняются во временные переменные   
     temp_value1 = a[a.index(min(a[i:]))]
     temp_value2 = a[i]

     # значения из временный переменных сохраняются в выражения слева
     a[i] = temp_value1
     a[a.index(min(a[i:]))] = temp_value2

Присвоение в a[i] меняет его значение и может изменить значение выражения a.index(min(a[i:])), что и видно в первой же перестановке.

Чинится фиксацией второго индекса j:

    j = a.index(min(a[i:]))
    print(i, j, a[i], a[j])
    a[i] , a[j] = a[j] , a[i]

В коде выше я добавил ещё отладочную печать, так как сортировка всё ещё не сортировка:

$ python sort.py 
0 13 78 -97
1 31 -32 -96
2 15 5 -94
3 2 39 -94
...

В последней строчке i = 3, j = 2. Индекс j не должен быть меньше i - минимум отыскивается в правой части списка. Но индекс минимума может найтись в левой, если в списке есть повторяющиеся значения. -94 - первое такое значение.

Ограничение на поиск индекса исправляет ситуацию:

    j = a.index(min(a[i:]), i) # второй аргумент запрещает смотреть налево
    assert i <= j              # утверждение проверяет правильность j
    a[i] , a[j] = a[j] , a[i]
→ Ссылка
Автор решения: Fox Fox

Может я слабо разбираюсь в очень умных вещах... Я пытался понять идеологию этой борьбы с проблемой, честно пытался... Понять стиль такой фразы "код на сортировку списка", увы, мне было сложно. Однако, если вопрос о сортировке списка, значит, ответ в учебнике наверняка есть! Как Вам такое, Илон Маск:

a.sort()
→ Ссылка