Сортировка списка списка с пользовательской функцией сравнения в Python
Я знаю, что есть несколько вопросов, названных так, но я не могу заставить их отвечать на работу.
У меня есть список списков, 50 раз 5 элементов. Теперь я хочу отсортировать этот список, применив специальную функцию сравнения к каждому элементу. Эта функция вычисляет соответствие списка, по которому элементы сортируются. Я создал две функции, сравнение и соответствие:
def compare(item1, item2):
return (fitness(item1) < fitness(item2))
и
def fitness(item):
return item[0]+item[1]+item[2]+item[3]+item[4]
Затем я попытался вызвать их:
sorted(mylist, cmp=compare)
или
sorted(mylist, key=fitness)
или
sorted(mylist, cmp=compare, key=fitness)
или
sorted(mylist, cmp=lambda x,y: compare(x,y))
Также я попробовал list.sort() с теми же параметрами. Но в любом случае функции не получают список в качестве аргумента, а < <26 > . Я понятия не имею, почему это происходит, в основном из С++, это противоречит любой идее функции обратного вызова для меня. Как я могу сортировать эти списки с помощью специальной функции?
Edit
Я нашел свою ошибку. В цепочке, которая создает исходный список, одна функция не возвращала ничего, кроме возвращаемого значения. Извините за беспокойство
Ответы
Ответ 1
>>> l = [list(range(i, i+4)) for i in range(10,1,-1)]
>>> l
[[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [7, 8, 9, 10], [6, 7, 8, 9], [5, 6, 7, 8], [4, 5, 6, 7], [3, 4, 5, 6], [2, 3, 4, 5]]
>>> sorted(l, key=sum)
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]]
Вышеупомянутые работы. Вы делаете что-то другое?
Обратите внимание, что ваша ключевая функция - это просто sum
; нет необходимости писать его явно.
Ответ 2
Кроме того, ваша функция сравнения неверна. Он должен возвращать -1, 0 или 1, а не логический, как у вас есть. Правильной функцией сравнения будет:
def compare(item1, item2):
if fitness(item1) < fitness(item2):
return -1
elif fitness(item1) > fitness(item2):
return 1
else:
return 0
Ответ 3
Вам нужно немного изменить свою функцию compare
и использовать functools.cmp_to_key
, чтобы передать ее в sorted
. Пример кода:
import functools
lst = [list(range(i, i+5)) for i in range(5, 1, -1)]
def fitness(item):
return item[0]+item[1]+item[2]+item[3]+item[4]
def compare(item1, item2):
return fitness(item1) - fitness(item2)
sorted(lst, key=functools.cmp_to_key(compare))
Вывод:
[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]]
Работы:)
Ответ 4
Поскольку ОП просил использовать пользовательскую функцию сравнения (и это также привело меня к этому вопросу), я хочу дать твердый ответ здесь:
Как правило, вы хотите использовать встроенную функцию sorted()
которая принимает собственный компаратор в качестве параметра. Мы должны обратить внимание на тот факт, что в Python 3 имя параметра и семантика изменились.
Как работает пользовательский компаратор
При предоставлении пользовательского компаратора он обычно должен возвращать целочисленное значение/значение с плавающей запятой, которое соответствует следующему шаблону (как в большинстве других языков программирования):
- вернуть отрицательное значение (
< 0
), когда левый элемент должен быть отсортирован перед правым элементом - возврат положительного (
> 0
) означает, что левый элемент должен быть отсортирован после правого элемента - вернуть
0
когда левый и правый элементы имеют одинаковый вес и должны быть расположены "одинаково" без приоритета
В частном случае вопроса OP можно использовать следующую пользовательскую функцию сравнения:
def compare(item1, item2):
return fitness(item1) - fitness(item2)
Использование операции "минус" - изящный трюк, поскольку он дает положительные значения, когда вес элемента 1 больше веса элемента 2. Следовательно, item1 будет отсортирован после item2.
Если вы хотите заменить порядок сортировки, просто return fitness(item2) - fitness(item1)
вычитание: return fitness(item2) - fitness(item1)
Вызов sorted() в Python 2
sorted(mylist, key=cmp(compare))
или же:
sorted(mylist, cmp=lambda item1, item2: fitness(item1) - fitness(item2))
Вызов sorted() в Python 3
from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(compare))
или же:
from functools import cmp_to_key
sorted(mylist, key=cmp_to_key(lambda item1, item2: fitness(item1) - fitness(item2)))