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


98

У Python 2.x я міг передавати власні функції сортованим та .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" і т. Д. Фактичні символи - це Unicodes і ще складніше, іноді голосні звуки приходять до і після консонентів, я зробив функцію користувацького порівняння, тому ця частина нормальна. Тільки проблема полягає в тому, що я не міг передати власну функцію порівняння на сортовану або .sort


ви пробували просто sorted(x)?
SilentGhost

@SilentGhost, Щоб переконатися, я просто спробував ще раз, звичайно, не працював, тому що моя оригінальна мова відсутня в підтримці списку локалів операційними системами для сортування.
ВИ

1
Ви можете обернути свій cmp як ключову функцію. Знайдіть на сайті HowToSorting cmp_to_key.
Френк

тут що - щось подібне stackoverflow.com/questions/49327344 / ...
Eziz Durdyyev

Відповіді:


50

Скористайтеся keyаргументом (і дотримуйтесь рецепту, як перетворити стару cmpфункцію у keyфункцію).

functoolsмає функцію, cmp_to_keyзгадану на docs.python.org/3.6/library/functools.html#functools.cmp_to_key


+1, схоже, що рецепт дає мені вирішення, але я думаю, що я втрачу деяку ефективність, передавши всі оператори порівняння < > = середньому чоловікові, оскільки мій оригінальний звичайний сорт написаний на С, він мав близько 1 / 2x швидкості сортування за замовчуванням.
ВИ

2
(Просто переглянув ваш профіль) Ваша компанія блокує доступ до Google та StackOverflow? Наскільки дурні вони можуть стати? Але щодо вашої відповіді: Мені буде цікаво фактичне зниження продуктивності. Ви можете timeitце зробити?
Тім Піцкер

4
Я зробив деякі орієнтири, виглядає приблизно в 4 рази повільніше, ніж передача спеціальної функції порівняння безпосередньо.
ВИ

2
Що робити, якщо мені потрібна і ключова функція, і функція cmp? Я хочу сортувати список словників за користувацьким ключем у кожному словнику. sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)дає TypeError: 'cmp' є недійсним аргументом ключового слова для цієї функції в Python 3.2 :(
bitek

4
functools має функцію cmp_to_key у стандартній бібліотеці: docs.python.org/3.6/library/functools.html
Martín Fixman

59

Використовуйте keyключове слово та functools.cmp_to_key для перетворення функції порівняння:

sorted(x, key=functools.cmp_to_key(customsort))

17

Замість митниці () вам потрібна функція, яка переводить кожне слово на щось, що 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, очевидно, повинна бути складнішою. Це має дати вам загальну думку.


Дякую +1, це так, як я думаю. але так як у моїй мові немає сепараторів слів і немає стандартних правил романізації, я думаю, що потрібен час на дослідження.
ВИ

9

Повний комплект прикладу лямбда python3 cmp_to_key:

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)

4

Я не знаю, чи це допоможе, але ви можете перевірити localeмодуль. Схоже, ви можете встановити локаль для своєї мови та використовувати locale.strcollдля порівняння рядків, використовуючи правила сортування вашої мови.


Це справедливо для популярних мов, але мою мову повністю не підтримують Операційні системи, ІКУ та unicode.org, так що це не викликає сумнівів, але +1 для гарної пропозиції.
ВИ

-2

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

sorted(x, key=somekeyfunc)

3
ключ приймає лише одну функцію параметра, cmp має 2 параметри, вони відрізняються поведінкою. і я щойно перевірив, помилився, бо ключове слово передає лише один параметр,TypeError: customsort() takes exactly 2 positional arguments (1 given)
ВАС
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.