Bagaimana cara menggunakan fungsi perbandingan khusus di Python 3?

98

Di Python 2.x , saya bisa meneruskan fungsi kustom ke fungsi sortir dan .sort

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

Karena, dalam bahasa saya , konsonan hadir dengan urutan ini

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

Tapi di Python 3.x , sepertinya saya tidak bisa memasukkan cmpkata kunci

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

Apakah ada alternatif atau haruskah saya menulis fungsi yang diurutkan sendiri juga?

Catatan: Saya menyederhanakan dengan menggunakan "k", "kh", dll. Karakter sebenarnya adalah Unicodes dan bahkan lebih rumit, kadang-kadang ada huruf vokal muncul sebelum dan sesudah konsonan, saya telah melakukan fungsi perbandingan kustom, Jadi bagian itu ok. Hanya masalahnya adalah saya tidak bisa meneruskan fungsi perbandingan kustom saya ke sort atau .sort

KAMU
sumber
sudahkah kamu mencoba sorted(x)?
SilentGhost
@SilentGhost, Untuk memastikan, saya baru mencoba lagi, Tentu saja tidak berfungsi, karena bahasa asli saya tidak ada dalam daftar lokal yang didukung oleh Sistem Operasi untuk melakukan penyortiran.
ANDA
1
Anda dapat membungkus cmp Anda sebagai fungsi kunci. Cari situs HowToSorting untuk cmp_to_key.
Frank
ini adalah sesuatu yang mirip stackoverflow.com/questions/49327344/…
Eziz Durdyyev

Jawaban:

50

Gunakan keyargumen (dan ikuti resep tentang cara mengubah cmpfungsi lama Anda menjadi keyfungsi).

functoolsmemiliki fungsi yang cmp_to_keydisebutkan di docs.python.org/3.6/library/functools.html#functools.cmp_to_key

Tim Pietzcker
sumber
+1, sepertinya resep memberi saya solusi, tetapi saya pikir saya akan kehilangan beberapa kinerja dengan meneruskan semua operator perbandingan < > = ke perantara, karena jenis kustom asli saya ditulis dalam C, kecepatannya sekitar 1 / 2x urutan default.
ANDA
2
(Baru saja melihat profil Anda) Perusahaan Anda memblokir akses ke Google dan StackOverflow? Betapa bodohnya mereka? Tetapi tentang tanggapan Anda: Saya tertarik dengan penurunan kinerja yang sebenarnya. Bisakah kamu timeititu
Tim Pietzcker
4
Saya telah melakukan beberapa tolok ukur, sepertinya sekitar 4x lebih lambat daripada meneruskan fungsi perbandingan C kustom secara langsung.
ANDA
2
Bagaimana jika saya membutuhkan fungsi kunci DAN fungsi cmp? Saya ingin mengurutkan daftar kamus dengan kunci khusus di setiap kamus. sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)memberikan TypeError: 'cmp' adalah argumen kata kunci yang tidak valid untuk fungsi ini, dengan Python 3.2 :(
bitek
4
functools memiliki fungsi cmp_to_key di perpustakaan standar: docs.python.org/3.6/library/functools.html
Martín Fixman
59

Gunakan keykata kunci dan functools.cmp_to_key untuk mengubah fungsi perbandingan Anda:

sorted(x, key=functools.cmp_to_key(customsort))
aknuds1
sumber
17

Alih-alih customort (), Anda memerlukan fungsi yang menerjemahkan setiap kata menjadi sesuatu yang Python sudah tahu cara mengurutkan. Misalnya, Anda dapat menerjemahkan setiap kata ke dalam daftar angka di mana setiap angka mewakili tempat setiap huruf muncul dalam alfabet Anda. Sesuatu seperti ini:

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)

Karena bahasa Anda menyertakan huruf banyak karakter, fungsi custom_key Anda jelas harus lebih rumit. Itu seharusnya memberi Anda gambaran umum.

Daniel Stutzbach
sumber
Terima kasih +1, begitulah menurut saya ICU. tetapi karena bahasa saya tidak memiliki pemisah kata dan tidak memiliki aturan romawi standar, menurut saya perlu waktu untuk melakukan penelitian.
ANDA
9

Contoh lambda python3 cmp_to_key lengkap:

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

bandingkan dengan penyortiran objek umum:

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)
Charlie 木匠
sumber
4

Saya tidak tahu apakah ini akan membantu, tetapi Anda dapat memeriksa localemodulnya. Sepertinya Anda dapat menyetel lokal ke bahasa Anda dan menggunakannya locale.strcolluntuk membandingkan string menggunakan aturan pengurutan bahasa Anda.

Mark Tolonen
sumber
Itu benar untuk bahasa populer tetapi bahasa saya tidak sepenuhnya didukung oleh Sistem Operasi, ICU, dan unicode.org, jadi itu tidak mungkin, tetapi +1 untuk saran yang bagus.
ANDA
-2

Gunakan keyargumen sebagai gantinya. Dibutuhkan fungsi yang mengambil nilai yang sedang diproses dan mengembalikan satu nilai memberikan kunci untuk digunakan untuk mengurutkan.

sorted(x, key=somekeyfunc)
Ignacio Vazquez-Abrams
sumber
3
key hanya menerima satu fungsi parameter, cmp memiliki 2 parameter, perilakunya berbeda. dan saya baru saja menguji, mendapat kesalahan, karena kata kunci kunci hanya melewatkan satu parameter,TypeError: customsort() takes exactly 2 positional arguments (1 given)
ANDA