Jak korzystać z niestandardowej funkcji porównania w Pythonie 3?


98

W Pythonie 2.x mogłem przekazać funkcję niestandardową do funkcji sortowanych i .sort

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

Ponieważ w moim języku w tej kolejności występują spółgłoski

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

Ale w Pythonie 3.x wygląda na to, że nie mogłem przekazać cmpsłowa kluczowego

>>> 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

Czy są jakieś alternatywy, czy też powinienem napisać własną posortowaną funkcję?

Uwaga: uprościłem, używając "k", "kh" itp. Rzeczywiste znaki to Unicody i jeszcze bardziej skomplikowane, czasami przed i po spółgłoskach pojawiają się samogłoski, zrobiłem niestandardową funkcję porównywania, więc ta część jest w porządku. Jedynym problemem jest to, że nie mogłem przekazać mojej niestandardowej funkcji porównania do sortowania lub .sort


próbowałeś właśnie sorted(x)?
SilentGhost

@SilentGhost, Aby się upewnić, po prostu spróbowałem ponownie, oczywiście nie działa, ponieważ mój oryginalny język nie znajduje się na liście ustawień regionalnych obsługiwanych przez systemy operacyjne do sortowania.
YOU

1
Możesz opakować swój cmp jako funkcję kluczową. Wyszukaj w serwisie HowToSorting cmp_to_key.
Frank

Odpowiedzi:


50

Użyj keyargumentu (i postępuj zgodnie z przepisem, jak przekonwertować starą cmpfunkcję na keyfunkcję).

functoolsma funkcję cmp_to_keywymienioną na docs.python.org/3.6/library/functools.html#functools.cmp_to_key


+1, wygląda na to, że przepis daje mi obejście, ale myślę, że stracę trochę wydajności, przekazując wszystkie operatory porównania < > = pośrednikowi, ponieważ moje oryginalne niestandardowe sortowanie jest napisane w C, miało około 1 / 2x prędkość domyślne sortowanie.
YOU

2
(Właśnie obejrzałem Twój profil) Twoja firma blokuje dostęp do Google i StackOverflow? Jak głupi mogą być? Ale jeśli chodzi o twoją odpowiedź: byłbym zainteresowany faktycznym spadkiem wydajności. Potrafisz timeitto?
Tim Pietzcker

4
Zrobiłem kilka testów porównawczych, wygląda na około 4x wolniej niż bezpośrednie przekazanie niestandardowej funkcji porównania C.
YOU

2
A jeśli potrzebuję zarówno funkcji klucza, jak i funkcji cmp? Chcę posortować listę słowników według niestandardowego klucza w każdym słowniku. sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)daje TypeError: 'cmp' jest nieprawidłowym argumentem słowa kluczowego dla tej funkcji, w Pythonie 3.2 :(
bitek

4
functools ma funkcję cmp_to_key w standardowej bibliotece: docs.python.org/3.6/library/functools.html
Martín Fixman


17

Zamiast Customort () potrzebujesz funkcji, która tłumaczy każde słowo na coś, co Python już wie, jak posortować. Na przykład, możesz przetłumaczyć każde słowo na listę liczb, gdzie każda cyfra reprezentuje miejsce, w którym każda litera występuje w Twoim alfabecie. Coś takiego:

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)

Ponieważ twój język zawiera wieloznakowe litery, twoja funkcja custom_key będzie oczywiście musiała być bardziej skomplikowana. To jednak powinno dać ci ogólny pomysł.


Dzięki +1, tak myślę na OIOM-ie. ale ponieważ mój język nie ma separatorów słów i nie ma standardowych reguł latynizacji, myślę, że zajmie to trochę czasu.
YOU

9

Kompletny przykład lambda cmp_to_key w Pythonie3:

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))

w porównaniu do zwykłego sortowania obiektów:

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

Nie wiem, czy to pomoże, ale możesz sprawdzić localemoduł. Wygląda na to, że możesz ustawić ustawienia regionalne na swój język i użyć go locale.strcolldo porównania ciągów znaków przy użyciu reguł sortowania w Twoim języku.


To prawda w przypadku popularnych języków, ale mój język nie jest w pełni obsługiwany przez systemy operacyjne, ICU i unicode.org, więc to wykluczone, ale +1 za dobrą sugestię.
YOU

-2

keyZamiast tego użyj argumentu. Pobiera funkcję, która przyjmuje przetwarzaną wartość i zwraca pojedynczą wartość, podając klucz do sortowania według.

sorted(x, key=somekeyfunc)

3
Klucz akceptuje tylko jedną funkcję parametryczną, cmp ma 2 parametry, mają różne zachowanie. i właśnie przetestowałem, dostałem błąd, ponieważ kluczowe słowo kluczowe przekazało tylko jeden parametr,TypeError: customsort() takes exactly 2 positional arguments (1 given)
YOU
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.