Как использовать пользовательскую функцию сравнения в Python 3?

В Python 2.x я мог передавать пользовательскую функцию функциям sorted и .sort.

>>> x=['kar','htar','har','ar']
>>>
>>> sorted(x)
['ar', 'har', 'htar', 'kar']
>>> 
>>> sorted(x,cmp=customsort)
['kar', 'htar', 'har', 'ar']

Потому что на Мой язык компоненты поставляются с таким порядком

"k","kh",....,"ht",..."h",...,"a"

Но в Python 3.x, похоже, я не смог передать cmp ключевое слово

>>> sorted(x,cmp=customsort)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'cmp' is an invalid keyword argument for this function

Есть ли альтернативы, или я должен написать свою собственную отсортированную функцию?

Примечание: я упростил, используя "k", "kh" и т. д. Фактические символы - это юникоды и даже более сложные, иногда гласные идут до и после компонентов, я сделал специальную функцию сравнения, так что эта часть в порядке. Проблема только в том, что я не смог передать свою пользовательскую функцию сравнения в sorted или .sort


person YOU    schedule 28.03.2010    source источник
comment
вы пробовали только sorted(x)?   -  person SilentGhost    schedule 28.03.2010
comment
@SilentGhost, Чтобы убедиться, я просто попробовал еще раз, конечно, не работает, потому что мой исходный язык не входит в список локалей, поддерживаемых операционными системами для сортировки.   -  person YOU    schedule 28.03.2010
comment
Вы можете обернуть свой cmp как ключевую функцию. Найдите cmp_to_key на сайте HowToSorting.   -  person Frank    schedule 02.08.2012
comment
вот что-то похожее на stackoverflow.com/questions / 49327344 /   -  person Eziz Durdyyev    schedule 17.03.2018


Ответы (6)


Используйте аргумент key (и следуйте рецепт о том, как преобразовать вашу старую cmp функцию в key функцию).

functools имеет функцию cmp_to_key, упомянутую в docs.python.org/3.6/library/ functools.html # functools.cmp_to_key

person Tim Pietzcker    schedule 28.03.2010
comment
+1, похоже, рецепт дает мне обходной путь, но я думаю, что я потеряю некоторую производительность, передав все операторы сравнения < > = среднему человеку, так как моя исходная пользовательская сортировка написана на C, она имела скорость около 1/2x сортировки по умолчанию. - person YOU; 28.03.2010
comment
(Только что посмотрел ваш профиль) Ваша компания блокирует доступ к Google и StackOverflow? Насколько они могут стать глупыми? Но по поводу вашего ответа: меня бы интересовало реальное снижение производительности. Вы можете timeit это? - person Tim Pietzcker; 28.03.2010
comment
Да, для блокировки Google они хотят, чтобы мы использовали goo.ne.jp (я думаю, их филиал), но я настраиваю прокси NTLM и создаю сценарий на стороне сервера на моем хостинге и туннелирую через него. Я не знаю, зачем нужен stackoverflow. - И конечно, сделаю несколько тестов. - person YOU; 28.03.2010
comment
Я провел несколько тестов, похоже, примерно в 4 раза медленнее, чем передача пользовательской функции сравнения C. - person YOU; 28.03.2010
comment
Что делать, если мне нужны и ключевая функция, и функция cmp? Я хочу отсортировать список словарей по индивидуальному ключу в каждом словаре. sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm) выдает TypeError: 'cmp' является недопустимым аргументом ключевого слова для этой функции в Python 3.2 :( - person Alex Bitek; 12.12.2014
comment
@ Dr.SkyLizard: Я не могу это проверить, но думаю, sorted_rows = sorted(rows, key=lambda x:locale.strxfrm(x['name'])) должен это сделать. - person Tim Pietzcker; 12.12.2014
comment
functools имеет функцию cmp_to_key в стандартной библиотеке: docs.python.org/3.6/library/ functools.html - person Martín Fixman; 03.02.2016

Используйте ключевое слово key и functools.cmp_to_key, чтобы преобразовать функцию сравнения:

sorted(x, key=functools.cmp_to_key(customsort))
person aknuds1    schedule 20.05.2014

Вместо customort () вам нужна функция, которая переводит каждое слово во что-то, что Python уже умеет сортировать. Например, вы можете перевести каждое слово в список чисел, где каждое число обозначает место каждой буквы в вашем алфавите. Что-то вроде этого:

my_alphabet = ['a', 'b', 'c']

def custom_key(word):
   numbers = []
   for letter in word:
      numbers.append(my_alphabet.index(letter))
   return numbers

x=['cbaba', 'ababa', 'bbaa']
x.sort(key=custom_key)

Поскольку ваш язык включает в себя многосимвольные буквы, ваша функция custom_key, очевидно, должна быть более сложной. Это должно дать вам общее представление.

person Daniel Stutzbach    schedule 28.03.2010
comment
Спасибо +1, я так думаю. но поскольку в моем языке нет разделителей слов и стандартных правил латинизации, я думаю, потребуется время для исследования. - person YOU; 28.03.2010

Полный пример лямбда-выражения cmp_to_key на python3:

from functools import cmp_to_key

nums = [28, 50, 17, 12, 121]
nums.sort(key=cmp_to_key(lambda x, y: 1 if str(x)+str(y) < str(y)+str(x) else -1))

сравните с обычной сортировкой объектов:

class NumStr:
    def __init__(self, v):
        self.v = v
    def __lt__(self, other):
        return self.v + other.v < other.v + self.v


A = [NumStr("12"), NumStr("121")]
A.sort()
print(A[0].v, A[1].v)

A = [obj.v for obj in A]
print(A)
person Charlie 木匠    schedule 04.07.2019

Не знаю, поможет ли это, но вы можете проверить модуль locale. Похоже, вы можете установить языковой стандарт на свой язык и использовать locale.strcoll для сравнения строк, используя правила сортировки вашего языка.

person Mark Tolonen    schedule 28.03.2010
comment
Это верно для популярных языков, но мой язык не полностью поддерживается операционными системами, ICU и unicode.org, так что это не вопрос, но +1 за хорошее предложение. - person YOU; 28.03.2010

Вместо этого используйте аргумент key. Он принимает функцию, которая принимает обрабатываемое значение и возвращает одно значение, дающее ключ для использования для сортировки.

sorted(x, key=somekeyfunc)
person Ignacio Vazquez-Abrams    schedule 28.03.2010
comment
key принимает только одну функцию параметра, cmp имеет 2 параметра, они различаются по поведению. и я только что протестировал, получил ошибку, потому что ключевое слово передает только один параметр, TypeError: customsort() takes exactly 2 positional arguments (1 given) - person YOU; 28.03.2010