你手里有了一个字典,想把它按"值"从大到小排个序做排名,却卡在字典没有 sort 方法上。举个具体场景:你做了一场投票,用字典记下了每个选项的票数;或者你爬了一篇文章,用字典记下了每个词出现的次数。不管是哪种,最后你都想知道"排在最前面的是谁"。答案很简单:用 Python 内置的 sorted() 函数,配合 key 参数告诉它"按值排",就能拿到排好序的结果。本文基于 Python 3.10 验证,演示三种按值排序的做法,并讲清取前 N 名、值相同时怎么排等坑。今天这篇文章,编程狮就用最通俗的语言把它讲透。
一、为什么字典不能直接 sort?先搞懂排序的对象
字典按值排序,指的是按每个键对应的那个数字大小,重新排列这些键值对。比如你统计了三种水果的销量 {"苹果": 30, "香蕉": 12, "橙子": 25},想看谁卖得最好,就得按 30、25、12 这个顺序排。
字典本身存的是"键 → 值"的映射,它关心的是"通过键快速查到值",并不天然知道该怎么按值排队。你可以把字典想象成一本电话簿:名字是键,号码是值;电话簿默认按名字排,但你突然想"按号码大小排一下",它就没这个自带功能。所以 Python 没有给字典设计 sort 方法,你写 dict.sort() 会直接抛出 AttributeError。
正确的做法是借用内置函数 sorted()。它不对原字典动手,而是接收一个可迭代对象,返回一个新的已排序列表。只要我们告诉它"按值排",问题就解决了。如果你刚接触 Python,建议先过一遍 Python 基础入门教程,把字典和函数这两个基础概念理顺,后面看代码会更轻松。
💡 小提示:Python 3.7 之后字典会保持插入顺序,但这只是"记住你放进来的先后",和"按值排序"完全是两回事,别被它误导。
说到底,字典按值排序这件事,本质是借用 sorted 把键值对按数值重新排队。理解这一点,后面所有写法都只是它的变体,不用死记硬背。
二、方法一:sorted + lambda 按值排序(最常用)
最通用、也最好懂的写法,是给 sorted() 传一个 key 参数。key 是一个函数,sorted 会用它从每个元素里"提取"出用来比较的那一部分。排序时,Python 比的不是整个元素,而是 key 算出来的那个结果。
字典的 items() 方法会返回一个个 (键, 值) 元组。我们要按"值"排,就让 key 返回元组的第 2 个元素,也就是下标 1 的位置:
scores = {"苹果": 30, "香蕉": 12, "橙子": 25}
# 按值从大到小(降序)排列
result = sorted(scores.items(), key=lambda x: x[1], reverse=True)
print(result)
# 输出:[('苹果', 30), ('橙子', 25), ('香蕉', 12)]
这里 lambda x: x[1] 的意思是:对每一个 (键, 值) 元组 x,取它的第 2 项(值)作为排序依据。reverse=True 表示降序;去掉它或写成 False,就是从小到大升序。
sorted 返回的是一个列表,里面是排好序的元组,原字典并不会被修改。如果你只想要排好序的"键"或只想要"值",可以在外面再套一层推导式,例如 [k for k, v in result] 就只取键。常用的字典方法记不住时,可以随手翻 Python 速查手册,把 items、keys、values 这些用法贴在手边。
三、方法二:用 operator.itemgetter 写法更简洁
如果你不喜欢写 lambda,标准库里的 operator.itemgetter 能办一模一样的事,而且可读性更高:
from operator import itemgetter
scores = {"苹果": 30, "香蕉": 12, "橙子": 25}
result = sorted(scores.items(), key=itemgetter(1), reverse=True)
print(result)
# 输出:[('苹果', 30), ('橙子', 25), ('香蕉', 12)]
itemgetter(1) 等价于 lambda x: x[1],都是"取元组的第 2 项"。在数据量很大时,itemgetter 通常比 lambda 稍快一点,因为少了一次函数调用开销。它还能一次取多项,比如 itemgetter(1, 0) 会返回 (值, 键) 这样的元组,配合排序就能实现"先按值、值相同再按键"。语法细节拿不准,在线编程词典 里能直接查到 operator 模块的说明。
⚠️ 注意:itemgetter(1) 是按位置取,普通元组用数字下标就好;别和按字段名取对象的方式搞混,否则会报 TypeError。
四、方法三与横向对比:取前 N 名、值相同怎么办
实际工作里,你往往不需要全部排序,只要前几名。排序后直接切片即可:
scores = {"苹果": 30, "香蕉": 12, "橙子": 25, "葡萄": 25}
top3 = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:3]
print(top3)
# 输出:[('苹果', 30), ('橙子', 25), ('葡萄', 25)]
当有两个值相同时(比如橙子和葡萄都是 25),Python 的排序是稳定的:值相同的元素会保持原来的先后顺序。如果你希望值相同时再按"键"排,可以把 key 写成一个元组:
top = sorted(scores.items(), key=lambda x: (x[1], x[0]), reverse=True)
下面把三种做法摆在一起对比:
| 做法 | 适用场景 | 优点 | 代价 |
|---|---|---|---|
| sorted + lambda | 绝大多数场景,逻辑直观 | 灵活,能写任意提取规则 | 大量数据时稍慢 |
| operator.itemgetter | 按固定位置取,追求简洁 | 可读性高、略快 | 复杂规则写不了 |
| 排序后切片 | 只要前 N 名 | 一行搞定 Top 榜 | 仍做了完整排序 |
选用建议:日常写业务代码,sorted + lambda 最顺手;追求极致可读或性能,选 itemgetter;只想拿榜单前几名,排序完切片就够了,没必要绕弯。当你下次再遇到字典按值排序的需求,直接套这套思路就能少踩坑。
总结
字典按值排序的核心逻辑只有一句话:调用内置的 sorted() 函数,并用 key 参数指定"按值比较"。具体做法是 key=lambda x: x[1] 取元组的第 2 项(值),reverse=True 控制降序。记住三个要点:
- sorted 不修改原字典,它返回一个新的列表;
- 要按"值"排就用 x[1],要按"键"排就用 x[0];
- 只要前几名,排序结果后面加 [:N] 切片就行。
想系统把 Python 学扎实,可以顺着下面的路径继续。
延伸学习
想把这块知识系统补齐,可以按这个顺序来:
- 想系统规划 Python 学习路线,可以参考 Python 系统学习路线;
- 想边学边练,编程实战课程 提供大量可上手的小项目。
常见问题
Q:sorted 会修改我原来的字典吗?
A:不会。sorted 是纯函数,返回一个新的已排序列表,原字典原封不动。若想"覆盖"原变量,把结果重新赋值回去即可。
Q:为什么返回的是列表而不是字典?
A:排序后顺序由"值"决定,而字典的语义是键到值的映射。sorted 统一返回列表最稳妥;若确实需要字典形式,可用 dict(排序结果) 转回去(Python 3.7+ 会保留该顺序)。
Q:值相同的两项,谁排在前面?
A:Python 的排序是稳定的,值相同时会保持原来的插入顺序。若想值相同再按键排,把 key 写成 (x[1], x[0]) 这样的元组即可。
Q:中文键或中文值会影响排序吗?
A:按数字值排序完全不受影响;若按中文键排序,会按字符编码比较,想按拼音或笔画排需要额外指定比较规则,不能只靠默认排序。

免费 AI IDE



