Sắp xếp danh sách Python tùy chỉnh


93

Tôi đang cấu trúc lại một số mã cũ của mình và bắt gặp điều này:

alist.sort(cmp_items)

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

Mã hoạt động (và tôi đã viết nó cách đây 3 năm!) Nhưng tôi không thể tìm thấy điều này được ghi lại ở bất kỳ đâu trong tài liệu Python và mọi người đều sử dụng sorted()để triển khai sắp xếp tùy chỉnh. Ai đó có thể giải thích tại sao điều này hoạt động?


sorted()sort()cung cấp phân loại tùy chỉnh theo cùng một cách, mô-đun hóa sự khác biệt trong quy ước gọi.
Russell Borogove

2
Thật vậy, điều xảy ra là việc sử dụng một keytham số được ưu tiên hơn là truyền một cmphàm. (Sau này thậm chí không được triển khai trong Python 3)
jsbueno

Nó hơi mơ hồ, phụ thuộc vào những gì các mục trong danh sách; mã của bạn yêu cầu chúng phải có một thuộc tính foo, nếu không nó sẽ bị hỏng. Tốt hơn nên xác định một __lt__()phương thức tùy chỉnh cho lớp của bạn, sau đó sorted()list.sort()sẽ hoạt động hiệu quả. (Btw, các đối tượng không còn cần phải xác định __cmp__(), chỉ cần __lt__(). Xem này
SMCI

Câu trả lời:


60

Nó được ghi lại ở đây .

Phương thức sort () nhận các đối số tùy chọn để kiểm soát các so sánh.

cmp chỉ định một hàm so sánh tùy chỉnh của hai đối số (mục danh sách) sẽ trả về số âm, số 0 hoặc số dương tùy thuộc vào việc đối số đầu tiên được coi là nhỏ hơn, bằng hoặc lớn hơn đối số thứ hai: cmp = lambda x, y : cmp (x.lower (), y.lower ()). Giá trị mặc định là không có.


Cảm ơn miles82 Tôi đã kiểm tra ở đây và không thể nhìn thấy nó trong phương pháp chữ ký docs.python.org/tutorial/datastructures.html
Lorenzo

Tôi không thấy văn bản tương tự trên trang bạn đã liên kết. Tài liệu có thay đổi không. Bên cạnh đó, khi tôi cố gắng sử dụng cmp, tôi nhận được TypeError: 'cmp' is an invalid keyword argument for this function. Chuyện gì đang xảy ra ở đây?
HelloGoodbye,

1
@HelloGoodbye sort () không có đối số cmp trong Python 3. Đây là câu trả lời cũ khi liên kết tài liệu dành cho Python 2. Bạn có thể tìm các tài liệu cũ tại đây hoặc đọc thêm về nó tại đây . Nếu bạn đang sử dụng Python 3, hãy sử dụng đối số khóa để thay thế.
miles82

Và nếu bạn thực sự muốn cung cấp một chức năng so sánh thì sao? Tôi muốn coi các số trong một chuỗi (có độ dài bất kỳ, được chọn ra một cách tham lam) là các ký hiệu, tương đương với cách các ký tự riêng lẻ được xử lý theo cách khác. Tôi biết làm thế nào để đạt được điều đó một cách tầm thường nếu tôi có thể cung cấp một hàm so sánh, nhưng không nếu tôi phải cung cấp một hàm chính. Tại sao điều này được thay đổi?
HelloGoodbye

Tôi đoán nó vẫn có thể đạt được nếu mỗi số chứa trong chuỗi được mã hóa bằng cách sử dụng mã hóa sắp xếp các số theo từ điển, chẳng hạn như mã hóa Levenshtein . Nhưng tôi coi đây nhiều hơn là một giải pháp cho thực tế là sortkhông sử dụng hàm so sánh làm đối số trong Python 3 và không phải là điều mà tôi thực sự muốn làm.
HelloGoodbye

104

Lưu ý thêm, đây là một giải pháp thay thế tốt hơn để thực hiện cùng một phân loại:

alist.sort(key=lambda x: x.foo)

Hay cách khác:

import operator
alist.sort(key=operator.attrgetter('foo'))

Kiểm tra Cách sắp xếp , nó rất hữu ích.


1
TIL về toán tử, rất hữu ích.
ffledgling

13

Cũng giống như ví dụ này. Bạn muốn sắp xếp danh sách này.

[('c', 2), ('b', 2), ('a', 3)]

đầu ra:

[('a', 3), ('b', 2), ('c', 2)]

bạn nên sắp xếp các bộ theo mục thứ hai, sau đó đến mục đầu tiên:

def letter_cmp(a, b):
    if a[1] > b[1]:
        return -1
    elif a[1] == b[1]:
        if a[0] > b[0]:
            return 1
        else:
            return -1
    else:
        return 1

Cuối cùng:

chỉ sort(letter_cmp)


4
Làm thế nào nó biết những gì danh sách để sắp xếp?
Cameron Monks

2
@CameronMonks yourList.sort (letter_cmp)
Minyc510

7

Điều này không hoạt động trong Python 3.

Bạn có thể sử dụng functools cmp_to_key để các hàm so sánh kiểu cũ hoạt động.

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

cmp_items_py3 = cmp_to_key(cmp_items)

alist.sort(cmp_items_py3)

1

Trong python3, bạn có thể viết:

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

alist = sorted(alist, key=cmp_to_key(cmp_items))

0

Thậm chí còn tốt hơn:

student_tuples = [
    ('john', 'A', 15),
    ('jane', 'B', 12),
    ('dave', 'B', 10),
]

sorted(student_tuples, key=lambda student: student[2])   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Lấy từ: https://docs.python.org/3/howto/sorting.html

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.