说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 内置 sorted() 函数的作用是按特定顺序(升序或降序)对给定可迭代对象(iterable,如列表和元组)的元素进行排序,并将其作为列表返回。
sorted() 具有三个参数,其中两个可选参数,它们都必须指定为关键字参数(传入需要参数名)。
sorted(iterable, /, *, key=None, reverse=False)
详细语法:
def sorted(__iterable: Iterable[_T],
*,
key: (_T) -> SupportsLessThan,
reverse: bool = ...) -> list[_T]
这三个参数是:
注:语法表达式中的
/
代表函数在此之前的参数必须是位置参数(直接传不能带关键字),目的是调用方法统一,节省代码量*
代表在此后的参数必须用关键字传入,传入需要参数名(如 reverse=True,而不是直接写 True),目的是让代码表意更加清晰、可读sorted() 返回的是一个排序后的列表。
内置的 sorted() 确保是稳定的。 如果一个排序确保不会改变比较结果相等的元素的相对顺序就称其为稳定的,这有利于进行多重排序(例如先按部门、再按薪级排序)。
对于更复杂的自定义排序,sorted() 采用可选的 key 参数指定一个函数,该函数在比较之前转换每个元素。key 函数接受 1 个值并返回1个值,返回的函数计算值(proxy)值用于排序中的比较。
例如,对于字符串列表,指定 key=len
(内置的 len()
函数)按长度对字符串进行排序,从最短到最长。排序对每个字符串调用 len()
,以获取代理长度值列表,然后使用这些代理值进行排序。
strs = ['ccc', 'aaaa', 'd', 'bb']
sorted(strs, key=len)
# ['d', 'bb', 'ccc', 'aaaa']
可以自定义一个函数,该函数接受一个值(这个值是序列中的每个元素),并返回代理值以指导排序。因此,key 传入的是一个可调用对象,这个对接接受序列中的元素。
# 不区分大小写的字符串比较
sorted("This is a test string from Andrew".split(), key=str.lower)
# ['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
对字符的排序是按照 unicode 的码位顺序进行排序的,但有一些细节实现比较复杂,todo(以后写)。
排序算法只使用项目之间的 <
比较。虽然定义一个__lt__()
(小于)方法就足以进行排序,但 PEP 8 建议实现所有六个比较功能("<" | ">" | "==" | ">=" | "<=" | "!="
)的特殊方法,这将有助于避免将相同的数据与依赖于不同底层方法的其他排序工具(如 max()
)一起使用时出现错误。实现所有六个比较功能的特殊方法也有助于避免混合类型比较的混淆,混合类型比较可以调用 __gt__()
方法。
对字符串、列表和元组进行排序:
# vowels list
py_list = ['e', 'a', 'u', 'o', 'i']
sorted(py_list)
# ['a', 'e', 'i', 'o', 'u']
# string
py_string = 'Python'
sorted(py_string)
# ['P', 'h', 'n', 'o', 't', 'y']
# vowels tuple
py_tuple = ('e', 'a', 'u', 'o', 'i')
sorted(py_tuple)
# ['a', 'e', 'i', 'o', 'u']
请注意,在所有情况都会返回排序后的列表,不认原数据是什么结构。
sorted() 函数接受一个 reverse 参数作为可选参数,设置 reverse=True 将按降序对 iterable 进行排序。
# set
py_set = {'e', 'a', 'u', 'o', 'i'}
print(sorted(py_set, reverse=True))
# ['u', 'o', 'i', 'e', 'a']
# dictionary
py_dict = {'e': 1, 'a': 2, 'u': 3, 'o': 4, 'i': 5}
sorted(py_dict, reverse=True)
# ['u', 'o', 'i', 'e', 'a']
# frozen set
frozen_set = frozenset(('e', 'a', 'u', 'o', 'i'))
sorted(frozen_set, reverse=True)
# ['u', 'o', 'i', 'e', 'a']
如果希望按照自己的实现进行排序,sorted() 还接受一个键函数作为可选参数。根据 key 函数的返回值,可以对给定的 iterable 进行排序。如 sorted(iterable, key=len)
,这里 len() 是 Python 的内置函数,用于计算对象的长度,在排序时会按照元素的长度进行排序。
# 使用第二个元素进行排序
def take_second(elem):
return elem[1]
# 随便给一个列表
random = [(2, 2), (3, 4), (4, 1), (1, 3)]
# 带关键字的排序列表
sorted_list = sorted(random, key=take_second)
# 打印 list
sorted_list
# [(4, 1), (2, 2), (1, 3), (3, 4)]
假设我们有以下列表:
# 科学奥林匹克竞赛中学生信息的嵌套列表
# 列表元素:(学生姓名,满分100分,年龄)
participant_list = [
('Alison', 50, 18),
('Terence', 75, 12),
('David', 75, 20),
('Jimmy', 90, 22),
('John', 45, 12)
]
我们希望对列表进行排序,使得分最高的学生位于开始位置,如果学生的分数相等,则必须对他们进行排序,以便年轻的参与者排在第一位。
我们可以通过返回元组而不是数字来实现这种多键排序。
两个元组可以通过从第一个元组开始比较它们的元素来进行比较。如果存在联系(元素相等),则比较第二个元素,依此类推。
>>> (1,3) > (1, 4)
False
>>> (1, 4) < (2,2)
True
>>> (1, 4, 1) < (2, 1)
True
让我们使用这个逻辑来构建排序逻辑。
# Nested list of student's info in a Science Olympiad
# List elements: (Student's Name, Marks out of 100 , Age)
participant_list = [
('Alison', 50, 18),
('Terence', 75, 12),
('David', 75, 20),
('Jimmy', 90, 22),
('John', 45, 12)
]
def sorter(item):
# 因为最高分在先,所以最小错误=最高分
error = 100 - item[1]
age = item[2]
return (error, age)
sorted(participant_list, key=sorter)
# [('Jimmy', 90, 22), ('Terence', 75, 12), ('David', 75, 20), ('Alison', 50, 18), ('John', 45, 12)]
由于排序逻辑函数很小,可以放在一行中,所以lambda函数在键内使用,而不是传递单独的函数名。上述程序可通过以下方式使用lambda函数编写:
# Nested list of student's info in a Science Olympiad
# List elements: (Student's Name, Marks out of 100 , Age)
participant_list = [
('Alison', 50, 18),
('Terence', 75, 12),
('David', 75, 20),
('Jimmy', 90, 22),
('John', 45, 12)
]
sorted(participant_list, key=lambda item: (100-item[1], item[2]))
# [('Jimmy', 90, 22), ('Terence', 75, 12), ('David', 75, 20), ('Alison', 50, 18), ('John', 45, 12)]
使用 functools.cmp_to_key()
可将老式的 cmp 函数转换为 key 函数,详见 标准库 functools 中的相关介绍。
案例 todo
列表还有 list.sort() 方法,其执行方式与 sorted() 相同,唯一的区别是 list.sort() 方法不返回任何值(其实是 None)并会更改原始列表。内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
更新时间:Jan. 16, 2022, 9:46 a.m. 标签:python 排序 sorted