Python 排序基础
在 Python 中排序常用的有 list.sort() 和 sorted() 。
基础用法
Python 内置的 sorted
可以对列表进行排序。例如:
sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
sorted
有一个 reverse
参数,默认为 False
,默认排序为升序。如果设置为 True
,则为降序:
sorted([5, 2, 3, 1, 4], reverse=True)
[5, 4, 3, 2, 1]
如果排序的对象是列表,那么还可以使用列表本身的 sort
:
my_nums = [5, 2, 3, 1, 4]
my_nums.sort()
my_nums
[1, 2, 3, 4, 5]
sort
同样有 reverse
参数:
my_nums = [5, 2, 3, 1, 4]
my_nums.sort(reverse=True)
my_nums
[5, 4, 3, 2, 1]
从上面的例子可以看出:
sort
只能用于列表,而sorted
不仅可以用于列表,还可以用于其他可迭代对象。sort
会改变列表本身,而sorted
不会改变可迭代对象本身,而是返回一个新的列表。
那么什么是“可迭代对象”呢?
要解释清楚不是三五句话可以讲完的,简单的说我们可以理解为可以循环取值的对像,例如 string
、tuple
、dictionary
、sets
、list
等等。
我们来看看例子:
my_string = '52314'
sorted(my_string)
['1', '2', '3', '4', '5']
# 字典是对 key 进行排序
my_dict = {'d': 5, 'b': 2, 'c':3, 'a': 4}
sorted(my_dict)
['a', 'b', 'c', 'd']
key 函数
list.sort()
和 sorted
都有一个 key 函数,其作用是相同的。把函数作为参数调用,这个函数会在排序之前作用每一个需要排序的对像。
例如上面例子中字典是对 key 进行了排序,那么如何根据 value 对 key 进行排序呢?
my_dict = {'d': 5, 'b': 2, 'c':3, 'a': 4}
sorted(my_dict, key=lambda x : my_dict[x])
['b', 'c', 'a', 'd']
来自 Python 官方文档的更多例子:
student_tuples = [
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10),
]
sorted(student_tuples, key=lambda student: student[2]) # 根据年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
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) # 根据年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
operator 模块函数
operatro 模块中的 itemgetter()
、 attrgetter()
和 methodcaller()
函数可以简化和加速上述的 key 函数的使用。
例如:
from operator import itemgetter, attrgetter
sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
复杂排序
下面的例子展示如何进行多个条件值反序:
sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
上述例子都是升序的,那么如果既有升序又有降序呢?
我们还是来看官方的示例:
s = sorted(student_objects, key=attrgetter('age')) # 先根据第二条件值年龄排序
sorted(s, key=attrgetter('grade'), reverse=True) # 然后根据第一条件值排序,使用降序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
上述内容可以抽象为一个函数:
def multisort(xs, specs):
for key, reverse in reversed(specs):
xs.sort(key=attrgetter(key), reverse=reverse)
return xs
multisort(list(student_objects), (('grade', True), ('age', False)))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
函数的变化
python 3 与 python 2 的函数定义是不同的,去掉了 cmp
参数。
来看一下定义,下面是 Python 2.7.6 中的定义:
>>> help(list.sort)
Help on method_descriptor:
sort(...)
L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
cmp(x, y) -> -1, 0, 1
>>> help(sorted)
Help on built-in function sorted in module __builtin__:
sorted(...)
sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list
sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list
下面是 Python 3.9.12 中的定义:
>>> help(list.sort)
Help on method_descriptor:
sort(self, /, *, key=None, reverse=False)
Sort the list in ascending order and return None.
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
order of two equal elements is maintained).
If a key function is given, apply it once to each list item and sort them,
ascending or descending, according to their function values.
The reverse flag can be set to sort in descending order.
>>> help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, /, *, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.