Индекс за пределами диапазона при использовании лямбда
Я немного запутался в лямбда-операторах на Python прямо сейчас. Следующий (рабочий) код сортирует список кортежей после количества вхождений первого элемента кортежей над первыми элементами всех кортежей:
tuples = [(2, 1, 8, 4), (3, 4, 8, 1), (3, 8, 1, 4), (4, 1, 8, 3),
(4, 8, 1, 3), (8, 8, 3, 1), (8, 1, 3, 4), (8, 4, 1, 3),
(8, 4, 3, 1)]
temp = list(zip(*tuples))
tuples.sort(key=lambda x: temp[0].count(x[0])
,reverse=True)
print(tuples)
Однако, если я сейчас попытаюсь пропустить создание "temp", то напишите это:
tuples = [(2, 1, 8, 4), (3, 4, 8, 1), (3, 8, 1, 4), (4, 1, 8, 3),
(4, 8, 1, 3), (8, 8, 3, 1), (8, 1, 3, 4), (8, 4, 1, 3),
(8, 4, 3, 1)]
tuples.sort(key=lambda x: list(zip(*tuples))[0].count(x[0])
,reverse=True)
print(tuples)
Выдает ошибку:
Traceback (most recent call last):
File "E:\Python-Programms\Sorting", line 6, in <module>
,reverse=True)
File "E:\Python-Programms\Sorting", line 5, in <lambda>
tuples.sort(key=lambda x: list(zip(*tuples)) [0].count(x[0])
IndexError: list index out of range
Почему возникает эта ошибка?
Ответы
Ответ 1
Если вы использовали функцию ванили и распечатали список во время сортировки, вы увидите, что список очищается во время операции сортировки (AFAIK это относится к CPython). Для пустого списка нет нулевого индекса:
def f(x):
print (tuples)
return ...
tuples.sort(key=f ,reverse=True)
[]
[]
[]
[]
[]
[]
[]
[]
[]
Заглядывание в источник CPython оставляет нам полезный комментарий, объясняющий это поведение:
static PyObject *
list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
{
...
/* The list is temporarily made empty, so that mutations performed
* by comparison functions can't affect the slice of memory we're
* sorting (allowing mutations during sorting is a core-dump
* factory, since ob_item may change).
*/
...
}
В свою первоначальную проблему, вместо того, чтобы повторно называть list.count
, что очень неэффективно, вы можете создать счетчик, а затем использовать его для сортировки:
from collections import Counter
c = Counter([x[0] for x in tuples])
tuples.sort(key=lambda x: c[x[0]], reverse=True)
Ответ 2
Список
list(zip(*tuples))
в вашей функции lambda
не является константой - она оценивается снова и снова на каждом этапе сортировки - каждый раз, когда вы вызываете функцию lambda
.
1 st шаг сортировки в порядке - функция lambda
- это именно то, что вы хотели. Но затем возникает проблема.
Список tuples
во время сортировки в нестабильном состоянии, может быть, пуст, может быть, что-то еще - алгоритм сортировки имеет свободу в нем. Его единственная обязанность заключается в том, чтобы отсортированный список был в правильном состоянии после выполнения полного сортировки.
2 nd шаг сортировки оценивает значение вашей функции lambda
на основе этого неустойчивого списка - кто знает его текущее значение?
Таким образом, использование отсортированного списка в функции key
не очень радует.