CC++ & Algorithm

Python排序函数 sorted

中等0
语言版本:C++
概述:sorted可以轻松地对列表、元组、字符串等可迭代对象排序,还能自定义排序规则。

用sorted轻松搞定排序——从扑克牌到成绩排名

当你手里有一堆乱七八糟的数字、名字或者成绩,想把它们按顺序排好,就像整理扑克牌一样,Python的sorted函数就是你的好帮手。它能把任何可迭代对象(比如列表、元组、字符串、字典等)按从小到大或从大到小的顺序排好,并返回一个崭新的排序后的列表。最重要的是,它不会破坏原来的数据,你可以随时拿着原样再排一次。

小提示:如果你只想在原列表上直接动手(比如“把这个列表排好,旧数据不要了”),可以用列表.sort()方法,但那只能用于列表。


1. 基本用法:从小到大排一排

所有可迭代对象都能用,比如一堆数字:

numbers = [4, 1, 9, 3, 6]  # 原始数字列表
sorted_numbers = sorted(numbers)  # 排序后得到新列表
print(sorted_numbers)  # 输出 [1, 3, 4, 6, 9]
print(numbers)         # 输出 [4, 1, 9, 3, 6]  原列表纹丝不动

生活例子:你有一包零食的价格(元):[4, 1, 9, 3, 6],想从便宜到贵排列,sorted一下就能看到最便宜的1元,最贵的9元。


2. 降序排序:从大到小

只要加上参数reverse=True,就能让顺序反过来。

scores = [85, 92, 78, 90]  # 考试成绩列表
sorted_scores = sorted(scores, reverse=True)  # 从高到低排
print(sorted_scores)  # 输出 [92, 90, 85, 78]  第一名92分

生活中的例子:班级月考后,你想知道谁最高分,谁最低分,用降序排一下,第一名就冒出来了。


3. 对字符串排序:按照字母顺序

字符串也可以排,但返回的是字符列表(每个字符单独出来)。按字母顺序(实际是按ASCII码,大写字母排在小写前面)。

name = "python"  # 字符串
sorted_chars = sorted(name)  # 排序后得到字符列表
print(sorted_chars)  # 输出 ['h', 'n', 'o', 'p', 't', 'y']
# 如果你想要回一个字符串,可以用join拼接
sorted_str = ''.join(sorted_chars)
print(sorted_str)  # 输出 "hnopty"

注意:大小写敏感,例如 "Banana" 和 "apple" 排序时,大写字母 'B'(ASCII 66)会排在小写 'a'(ASCII 97)前面,所以 "Banana" 会排在 "apple" 前面。如果你想要忽略大小写,可以用 key=str.lower


4. 对字典排序:按键或按值

字典本身是无序的,但我们可以对它的键排序,或者对它的“键值对”按值排序。

4.1 只排字典的键

sorted(字典) 默认会返回一个排好序的键列表。比如你有一本班级年龄字典,想按名字(键)排序:

ages = {'小明':12, '小红':11, '小刚':13}  # 姓名:年龄
sorted_keys = sorted(ages)  # 对键排序
print(sorted_keys)  # 输出 ['小明', '小刚', '小红']  按字典序(汉字按Unicode码)

4.2 按字典的值排序

如果想按年龄从小到大排,需要获取字典的“键值对”列表(用.items()),然后用key参数指定按第二个元素(年龄)比较。

ages = {'小明':12, '小红':11, '小刚':13}
# .items() 返回类似 [('小明',12), ('小红',11), ('小刚',13)] 的列表
sorted_by_age = sorted(ages.items(), key=lambda x: x[1])  # 按年龄升序
print(sorted_by_age)  
# 输出 [('小红', 11), ('小明', 12), ('小刚', 13)]

生活例子:体育课排队时,老师想按身高(值)从矮到高叫名字,用这个就能得到名字和身高的有序列表。


5. 自定义排序:用key参数为所欲为

sorted最强大的地方是key参数,它允许你指定一个“变换函数”,让排序依据这个函数的结果。例如按字符串长度排序:

words = ["apple", "pie", "banana", "kiwi"]  # 单词列表
sorted_words = sorted(words, key=len)  # 按长度升序
print(sorted_words)  # 输出 ['pie', 'kiwi', 'apple', 'banana']
# pie长度3,kiwi长度4,apple长度5,banana长度6

更复杂的情况:比如你有学生成绩元组 (姓名, 分数),想按分数从高到低排序(降序),同时分数相同的按姓名排序(升序),可以用key返回一个元组:

student_scores = [('小明', 95), ('小红', 88), ('小刚', 95), ('小美', 88)]
# 先按分数降序,分数相同再按姓名升序
sorted_students = sorted(student_scores, key=lambda x: (-x[1], x[0]))
print(sorted_students)  
# 输出 [('小明', 95), ('小刚', 95), ('小美', 88), ('小红', 88)]
# 注意:-x[1] 让分数变成负数,实现降序;然后x[0] 作为第二关键字

提示:key函数在排序前会作用于每个元素,根据返回值大小来定顺序。返回一个元组时,会依次比较元组内的每个部分。


6. 常见错误与注意事项

  • 误区1:把sorted的结果直接赋值给原变量,以为原对象变了

    items = [3,1,2]
    sorted(items)  # 忘了赋值,结果丢了
    print(items)   # 还是 [3,1,2]
    

    正确做法:items = sorted(items) 或者用 items.sort()

  • 误区2:对字典直接用sorted,以为会返回排序后的字典
    sorted(字典) 返回的是键的列表,不是字典。如果需要排序后的“键值对列表”,用 sorted(字典.items())

  • 误区3:想按字符串中的数字排序却直接排字符串
    例如 ['a2', 'a10', 'a1'] 按字符串排会得到 ['a1', 'a10', 'a2'](因为'1'<'10'<'2'按字符比较),正确做法是用key提取数字:

    items = ['a2', 'a10', 'a1']
    sorted_items = sorted(items, key=lambda x: int(x[1:]))  # 提取后面的数字转int
    print(sorted_items)  # ['a1', 'a2', 'a10']
    
  • 误区4:在key函数中使用可变类型(如列表)作为返回值
    key应该返回可比较的不可变类型(数字、字符串、元组等)。例如不要用 key=lambda x: x.sort() 之类。

  • 误区5:忽略reversekey的搭配
    如果既要降序又要特殊规则,可以 reverse=True,也可以像前面-x[1]那样取负值。但混合使用时注意逻辑。


7. 完整可运行示例:处理成绩单

下面是一个完整的小程序,模拟老师处理全班考试分数,按总分排名,并输出前五名。

# 学生成绩字典:姓名 -> (语文, 数学, 英语)
student_grades = {
    '小明': (90, 85, 92),
    '小红': (88, 90, 95),
    '小刚': (92, 80, 88),
    '小美': (85, 92, 90),
    '小华': (95, 88, 80)
}

# 计算总分,并存储为列表
grades_list = []  # 用来存放 (姓名, 总分) 的元组
for name, scores in student_grades.items():
    total = sum(scores)  # 计算总分
    grades_list.append((name, total))  # 添加元组

# 按总分降序排序(从高到低)
sorted_grades = sorted(grades_list, key=lambda x: x[1], reverse=True)

print("=== 成绩排名(前五名)===")
for rank, (name, total) in enumerate(sorted_grades[:5], start=1):
    print(f"第{rank}名:{name},总分{total}分")

运行输出示例:

=== 成绩排名(前五名)===
第1名:小红,总分273分
第2名:小明,总分267分
第3名:小美,总分267分
第4名:小刚,总分260分
第5名:小华,总分263分

(注意:小明和小美总分相同,排序结果依赖于稳定排序,这里没有指定第二关键字,所以保持原顺序。)


8. 相关知识点

  • 列表.sort() 方法:如果你不需要保留原列表,直接在原列表上修改,用 列表.sort() 更高效(不创建新列表)。它和 sortedkeyreverse 参数用法完全一样。
  • lambda匿名函数:在key里经常用的 lambda x: x[1] 是一个简短的函数,相当于 def get_value(x): return x[1]。掌握lambda能让代码更简洁。
  • 元组排序的比较规则:当key返回元组时,先比较第一个元素,相等再比较第二个,以此类推。
  • operator模块:提供 itemgetterattrgetter 等函数,可以替代lambda,在某些场景下更高效(如 sorted(grades_list, key=itemgetter(1)))。
  • cmp参数(Python 2):在Python 3中 cmp 已经移除,全用 key 实现。若需自定义比较器,可以用 functools.cmp_to_key 转换,但不常用。

排序是编程中的基础操作,在CSP-J考试中经常出现在查找、去重、贪心等题目里。学会 sorted,很多问题都能迎刃而解。

例题精讲

1单选题

执行以下代码后,变量 result 的值是什么? result = sorted([3, 1, 2])

A[3, 1, 2]
B[1, 2, 3]
C[2, 1, 3]
DNone
2判断题

sorted() 函数会直接修改原列表的顺序,而 list.sort() 则返回一个新列表。

3填空题
给定一个字符串列表 words = ['apple', 'kiwi', 'banana', 'pear'],请按字符串长度从小到大排序,将结果存入变量 sorted_words。
words = ['apple', 'kiwi', 'banana', 'pear']
sorted_words = sorted(words, key=___)
4单选题

若要对列表 [5, 2, 8, 1] 进行降序排序,下列哪个写法是正确的?

Asorted([5, 2, 8, 1], reverse=True)
Bsorted([5, 2, 8, 1], reverse=False)
Csorted([5, 2, 8, 1], descending=True)
Dsorted([5, 2, 8, 1], order='desc')
5填空题
有一个字典 scores = {'Alice': 88, 'Bob': 72, 'Cathy': 95},请按值(分数)从高到低排序,并输出排序后的 (姓名, 分数) 列表。
scores = {'Alice': 88, 'Bob': 72, 'Cathy': 95}
sorted_list = sorted(scores.items(), key=___, reverse=True)
print(sorted_list)