Hướng dẫn sort multiple keys python - sắp xếp nhiều khóa python

Câu trả lời này hoạt động cho bất kỳ loại cột nào trong từ điển - cột phủ định không cần phải là một số.

def multikeysort(items, columns):
    from operator import itemgetter
    comparers = [((itemgetter(col[1:].strip()), -1) if col.startswith('-') else
                  (itemgetter(col.strip()), 1)) for col in columns]
    def comparer(left, right):
        for fn, mult in comparers:
            result = cmp(fn(left), fn(right))
            if result:
                return mult * result
        else:
            return 0
    return sorted(items, cmp=comparer)

Bạn có thể gọi nó như thế này:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item

Hãy thử nó với một trong hai cột phủ định. Bạn sẽ thấy thứ tự sắp xếp đảo ngược.

Tiếp theo: Thay đổi nó để nó không sử dụng thêm lớp ....


2016-01-17

Lấy cảm hứng từ câu trả lời này Cách tốt nhất để có được mục đầu tiên từ một điều kiện phù hợp với điều kiện là gì ?, Tôi đã rút ngắn mã:

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)

Trong trường hợp bạn thích mã của bạn terse.


Muộn hơn 2016-01-17

Điều này hoạt động với Python3 (loại bỏ đối số

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
1 thành
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
2):

from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))

Lấy cảm hứng từ câu trả lời này làm thế nào tôi nên sắp xếp tùy chỉnh trong Python 3?

Tác giả

Andrew Dalke và Raymond Hettinger

Phóng thích

0.1

Danh sách Python có phương thức

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
3 tích hợp để sửa đổi danh sách tại chỗ. Ngoài ra còn có một chức năng tích hợp
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4 xây dựng một danh sách được sắp xếp mới từ một điều khác.

Trong tài liệu này, chúng tôi khám phá các kỹ thuật khác nhau để sắp xếp dữ liệu bằng Python.

Sắp xếp những điều cơ bản

Một loại tăng dần đơn giản là rất dễ dàng: chỉ cần gọi hàm

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4. Nó trả về một danh sách được sắp xếp mới:

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

Bạn cũng có thể sử dụng phương pháp

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
3. Nó sửa đổi danh sách tại chỗ (và trả về
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
7 để tránh nhầm lẫn). Thông thường, nó ít thuận tiện hơn
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4 - nhưng nếu bạn không cần danh sách ban đầu, thì nó lại hiệu quả hơn một chút.

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]

Một điểm khác biệt khác là phương pháp

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
3 chỉ được xác định cho danh sách. Ngược lại, hàm
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4 chấp nhận bất kỳ điều gì có thể.

>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

Chức năng chính¶

Cả

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
3 và
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4 đều có tham số chính để chỉ định hàm (hoặc có thể gọi khác) để được gọi trên mỗi phần tử danh sách trước khi so sánh.

Ví dụ: ở đây, một so sánh chuỗi không nhạy cảm trường hợp:

>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

Giá trị của tham số khóa phải là một hàm (hoặc có thể gọi khác) có một đối số duy nhất và trả về một khóa để sử dụng cho mục đích sắp xếp. Kỹ thuật này nhanh vì hàm chính được gọi chính xác một lần cho mỗi bản ghi đầu vào.

Một mẫu phổ biến là sắp xếp các đối tượng phức tạp bằng cách sử dụng một số chỉ số đối tượng là các khóa. Ví dụ:

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

Kỹ thuật tương tự hoạt động cho các đối tượng với các thuộc tính được đặt tên. Ví dụ:

>>> class Student:
...     def __init__(self, name, grade, age):
...         self.name = name
...         self.grade = grade
...         self.age = age
...     def __repr__(self):
...         return repr((self.name, self.grade, self.age))

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

Chức năng mô -đun vận hành

Các mẫu chức năng khóa được hiển thị ở trên là rất phổ biến, do đó, Python cung cấp các chức năng tiện lợi để làm cho các chức năng của người truy cập dễ dàng và nhanh hơn. Mô -đun

from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))
3 có hàm
from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))
4,
from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))
5 và
from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))
6.

Sử dụng các chức năng đó, các ví dụ trên trở nên đơn giản và nhanh hơn:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
0

Các chức năng mô -đun toán tử cho phép nhiều cấp độ sắp xếp. Ví dụ, để sắp xếp theo cấp độ sau đó theo tuổi:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
1

Tăng dần và giảm dần¶

Cả

from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
3 và
from operator import itemgetter as i

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, cmp=comparer)
4 đều chấp nhận tham số ngược với giá trị boolean. Điều này được sử dụng để gắn cờ các loại giảm dần. Ví dụ: để lấy dữ liệu của học sinh theo thứ tự tuổi ngược:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
2

Sắp xếp sự ổn định và các loại phức tạp

Các loại được đảm bảo là ổn định. Điều đó có nghĩa là khi nhiều bản ghi có cùng một khóa, thứ tự ban đầu của chúng được bảo tồn.

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
3

Lưu ý cách hai bản ghi cho Blue giữ lại thứ tự ban đầu của họ để

from operator import itemgetter as i
from functools import cmp_to_key

def cmp(x, y):
    """
    Replacement for built-in function cmp that was removed in Python 3

    Compare the two objects x and y and return an integer according to
    the outcome. The return value is negative if x < y, zero if x == y
    and strictly positive if x > y.

    https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
    """

    return (x > y) - (x < y)

def multikeysort(items, columns):
    comparers = [
        ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
        for col in columns
    ]
    def comparer(left, right):
        comparer_iter = (
            cmp(fn(left), fn(right)) * mult
            for fn, mult in comparers
        )
        return next((result for result in comparer_iter if result), 0)
    return sorted(items, key=cmp_to_key(comparer))
9 được đảm bảo trước
>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
0.

Khách sạn tuyệt vời này cho phép bạn xây dựng các loại phức tạp trong một loạt các bước sắp xếp. Ví dụ, để sắp xếp dữ liệu học sinh bằng cấp giảm dần và sau đó tăng dần tuổi, hãy sắp xếp tuổi trước và sau đó sắp xếp lại bằng cấp:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
4

Điều này có thể được trừu tượng hóa thành một hàm trình bao bọc có thể lấy một danh sách và bộ dữ liệu của trường và đặt hàng để sắp xếp chúng trên nhiều đường chuyền.

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
5

Thuật toán TIMSORT được sử dụng trong Python thực hiện nhiều loại hiệu quả vì nó có thể tận dụng bất kỳ thứ tự nào đã có trong bộ dữ liệu.

Trang trí-sort-undecignor¶

Idiom này được gọi là trang trí-dort-undeconation sau ba bước của nó:

  • Đầu tiên, danh sách ban đầu được trang trí với các giá trị mới kiểm soát thứ tự sắp xếp.

  • Thứ hai, danh sách trang trí được sắp xếp.

  • Cuối cùng, các trang trí được loại bỏ, tạo một danh sách chỉ chứa các giá trị ban đầu theo thứ tự mới.

Ví dụ, để sắp xếp dữ liệu của học sinh theo cấp bằng cách sử dụng phương pháp DSU:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
6

Thành ngữ này hoạt động vì các bộ dữ liệu được so sánh từ vựng; Các mục đầu tiên được so sánh; Nếu chúng giống nhau thì các mục thứ hai được so sánh, v.v.

Không cần thiết hoàn toàn cần thiết trong tất cả các trường hợp để đưa Chỉ số I vào danh sách được trang trí, nhưng bao gồm cả nó mang lại hai lợi ích:

  • Sắp xếp ổn định - nếu hai mục có cùng một khóa, đơn đặt hàng của chúng sẽ được bảo tồn trong danh sách được sắp xếp.

  • Các mặt hàng ban đầu không phải so sánh vì thứ tự của các bộ dữ liệu được trang trí sẽ được xác định nhiều nhất là hai mặt hàng đầu tiên. Vì vậy, ví dụ danh sách ban đầu có thể chứa các số phức tạp không thể được sắp xếp trực tiếp.

Một cái tên khác cho thành ngữ này là Schwartzian Transform, sau Randal L. Schwartz, người đã phổ biến nó trong số các lập trình viên Perl.

Bây giờ việc sắp xếp Python cung cấp các chức năng chính, kỹ thuật này không cần thiết.

Các chức năng so sánh

Không giống như các chức năng chính trả về giá trị tuyệt đối để sắp xếp, hàm so sánh tính toán thứ tự tương đối cho hai đầu vào.

Ví dụ, thang đo cân bằng so sánh hai mẫu cho một thứ tự tương đối: nhẹ hơn, bằng nhau hoặc nặng hơn. Tương tự như vậy, một hàm so sánh như

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
1 sẽ trả về giá trị âm cho ít hơn, 0 nếu các đầu vào bằng nhau hoặc giá trị dương cho lớn hơn.

Người ta thường gặp các hàm so sánh khi dịch thuật toán từ các ngôn ngữ khác. Ngoài ra, một số thư viện cung cấp các chức năng so sánh như là một phần của API của họ. Ví dụ,

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
2 là một hàm so sánh.

Để phù hợp với các tình huống đó, Python cung cấp

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
3 để bọc chức năng so sánh để làm cho nó có thể sử dụng được như một hàm chính:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
     {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
     {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
     {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
     {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
     {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
for item in a:
    print item
7

Vụn vặt¶

  • Để sắp xếp nhận thức địa phương, hãy sử dụng

    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    4 cho chức năng chính hoặc
    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    2 cho hàm so sánh. Điều này là cần thiết bởi vì các thứ tự sắp xếp theo thứ tự bảng chữ cái có thể thay đổi giữa các nền văn hóa ngay cả khi bảng chữ cái cơ bản là như nhau.

  • Tham số ngược vẫn duy trì sự ổn định sắp xếp (để các bản ghi có các khóa bằng nhau giữ lại thứ tự ban đầu). Thật thú vị, hiệu ứng đó có thể được mô phỏng mà không cần tham số bằng cách sử dụng hàm

    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    6 tích hợp hai lần:

    b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]
    
    a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
    for item in a:
        print item
    
    8

  • Các thói quen sắp xếp sử dụng

    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    7 khi so sánh giữa hai đối tượng. Vì vậy, thật dễ dàng để thêm một thứ tự sắp xếp tiêu chuẩn vào một lớp bằng cách xác định phương thức
    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    8:

    b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]
    
    a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
    for item in a:
        print item
    
    9

    Tuy nhiên, lưu ý rằng

    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    7 có thể quay trở lại bằng cách sử dụng
    >>> a = [5, 2, 3, 1, 4]
    >>> a.sort()
    >>> a
    [1, 2, 3, 4, 5]
    
    0 nếu
    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    
    8 không được thực hiện (xem
    >>> a = [5, 2, 3, 1, 4]
    >>> a.sort()
    >>> a
    [1, 2, 3, 4, 5]
    
    2).

  • Các chức năng chính không cần phải phụ thuộc trực tiếp vào các đối tượng được sắp xếp. Một chức năng chính cũng có thể truy cập các tài nguyên bên ngoài. Chẳng hạn, nếu các lớp học sinh được lưu trữ trong từ điển, chúng có thể được sử dụng để sắp xếp một danh sách riêng các tên sinh viên:

    from operator import itemgetter as i
    
    def multikeysort(items, columns):
        comparers = [
            ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
            for col in columns
        ]
        def comparer(left, right):
            comparer_iter = (
                cmp(fn(left), fn(right)) * mult
                for fn, mult in comparers
            )
            return next((result for result in comparer_iter if result), 0)
        return sorted(items, cmp=comparer)
    
    0