Подтвердить что ты не робот

Сортировка списка списка с пользовательской функцией сравнения в 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 Я нашел свою ошибку. В цепочке, которая создает исходный список, одна функция не возвращала ничего, кроме возвращаемого значения. Извините за беспокойство

4b9b3361

Ответ 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)))