Làm thế nào để sử dụng một hàm so sánh tùy chỉnh trong Python 3?


98

Trong Python 2.x , tôi có thể chuyển hàm tùy chỉnh sang các hàm được sắp xếp và .sort

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

Bởi vì, trong ngôn ngữ của Tôi , những người ủng hộ đi kèm với thứ tự này

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

Nhưng trong Python 3.x , có vẻ như tôi không thể chuyển cmptừ khóa

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

Có lựa chọn thay thế nào không hay tôi cũng nên viết hàm được sắp xếp của riêng mình?

Lưu ý: Tôi đã đơn giản hóa bằng cách sử dụng "k", "kh", v.v. Các ký tự thực tế là Unicodes và thậm chí còn phức tạp hơn, đôi khi có nguyên âm đứng trước và sau các thành phần, tôi đã thực hiện chức năng so sánh tùy chỉnh, vậy là xong phần đó. Chỉ có vấn đề là tôi không thể chuyển hàm so sánh tùy chỉnh của mình sang dạng sắp xếp hoặc .sort


bạn đã thử chỉ sorted(x)?
SilentGhost

@SilentGhost, Để chắc chắn, tôi vừa thử lại, Tất nhiên là không hoạt động, bởi vì ngôn ngữ gốc của tôi không nằm trong danh sách ngôn ngữ được Hệ điều hành hỗ trợ để thực hiện việc phân loại.
YOU

1
Bạn có thể bọc cmp của mình như một chức năng chính. Tìm kiếm cmp_to_key trên trang web HowToSorting.
Frank

đây là một cái gì đó tương tự stackoverflow.com/questions/49327344/…
Eziz Durdyyev

Câu trả lời:


50

Sử dụng keyđối số (và làm theo công thức về cách chuyển đổi cmphàm cũ của bạn thành một keyhàm).

functoolscó một chức năng cmp_to_keyđược đề cập tại docs.python.org/3.6/library/functools.html#functools.cmp_to_key


+1, có vẻ như công thức cung cấp cho tôi một cách giải quyết, nhưng tôi nghĩ rằng tôi sẽ mất một số hiệu suất khi chuyển tất cả các toán tử so sánh < > = cho người trung gian, vì loại tùy chỉnh ban đầu của tôi được viết bằng C, nó có tốc độ khoảng 1/2 lần là sắp xếp mặc định.
YOU

2
(Chỉ cần xem hồ sơ của bạn) Công ty của bạn đang chặn quyền truy cập vào Google và StackOverflow? Làm thế nào ngu ngốc họ có thể nhận được? Nhưng về câu trả lời của bạn: Tôi quan tâm đến việc giảm hiệu suất thực tế. Bạn có thể timeitnó?
Tim Pietzcker

4
Tôi đã thực hiện một số điểm chuẩn, có vẻ như chậm hơn khoảng 4 lần so với việc chuyển trực tiếp chức năng so sánh C tùy chỉnh.
YOU

2
Điều gì sẽ xảy ra nếu tôi cần cả hàm chính VÀ hàm cmp? Tôi muốn sắp xếp danh sách các từ điển bằng một khóa tùy chỉnh trong mỗi từ điển. sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)cung cấp cho TypeError: 'cmp' là một đối số từ khóa không hợp lệ cho hàm này, trong Python 3.2 :(
cắnk 12/1214

4
functools có hàm cmp_to_key trong thư viện tiêu chuẩn: docs.python.org/3.6/library/functools.html
Martín Fixman


17

Thay vì hải quan (), bạn cần một hàm dịch từng từ thành một thứ mà Python đã biết cách sắp xếp. Ví dụ: bạn có thể dịch từng từ thành một danh sách các số trong đó mỗi số đại diện cho vị trí mỗi chữ cái xuất hiện trong bảng chữ cái của bạn. Một cái gì đó như thế này:

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)

Vì ngôn ngữ của bạn bao gồm các chữ cái nhiều ký tự, nên hàm custom_key của bạn rõ ràng sẽ cần phức tạp hơn. Tuy nhiên, điều đó sẽ cung cấp cho bạn ý tưởng chung.


Cảm ơn +1, đó là ICU theo cách tôi nghĩ. nhưng vì ngôn ngữ của tôi không có bộ tách từ và không có các quy tắc La tinh tiêu chuẩn, tôi nghĩ sẽ mất thời gian để nghiên cứu.
YOU

9

Một ví dụ hoàn chỉnh về python3 cmp_to_key lambda:

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

so sánh với phân loại đối tượng thông thường:

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

Tôi không biết liệu điều này có hữu ích hay không, nhưng bạn có thể kiểm tra localemô-đun. Có vẻ như bạn có thể đặt ngôn ngữ cho ngôn ngữ của mình và sử dụng locale.strcollđể so sánh các chuỗi bằng cách sử dụng các quy tắc sắp xếp của ngôn ngữ của bạn.


Điều đó đúng với các ngôn ngữ phổ biến nhưng ngôn ngữ của tôi không được Hệ điều hành, ICU và unicode.org hỗ trợ đầy đủ, do đó, điều đó không đúng, nhưng +1 cho đề xuất tốt.
YOU

-2

Sử dụng keyđối số để thay thế. Nó sử dụng một hàm nhận giá trị đang được xử lý và trả về một giá trị duy nhất cung cấp cho khóa sử dụng để sắp xếp theo.

sorted(x, key=somekeyfunc)

3
key chỉ chấp nhận một hàm tham số, cmp có 2 tham số, chúng là hành vi khác nhau. và tôi vừa kiểm tra, đã gặp lỗi, vì từ khóa chính chỉ truyền một tham số,TypeError: customsort() takes exactly 2 positional arguments (1 given)
BẠN
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.