一、开篇:排序——数据处理的基本功
排序是编程中最常见的操作之一。python提供了两个排序工具:list.sort()(原地排序)和sorted()(返回新排序结果)。其中sorted()更灵活、更通用——它能排序任何可迭代对象,还能自定义排序规则。
⌨️ 先看最基础的用法:
# sorted()的基本用法 numbers = [3, 1, 4, 1, 5, 9, 2, 6] sorted_numbers = sorted(numbers) print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9] print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6] ← 原列表不变! # list.sort()——原地排序,直接修改原列表 numbers.sort() print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9] ← 被修改了 # 💡 关键区别: # sorted(iterable) → 返回新列表,原数据不变,可用于任何可迭代对象 # list.sort() → 原地排序,不返回新列表,只能用于列表
💡 sorted()的核心优势在于它的key参数——让你能按任意规则排序,这个参数是python排序系统的灵魂。
二、sorted()的基本参数
2.1 三个参数详解
# sorted(iterable, key=none, reverse=false) # iterable: 要排序的可迭代对象 # key: 排序依据的函数(接收每个元素,返回用于比较的值) # reverse: 是否降序(true=降序,false=升序) # reverse参数——升降序控制 numbers = [3, 1, 4, 1, 5] print(sorted(numbers)) # [1, 1, 3, 4, 5] 升序 print(sorted(numbers, reverse=true)) # [5, 4, 3, 1, 1] 降序 # key参数——自定义排序依据 words = ["banana", "apple", "cherry", "date", "elderberry"] # 默认排序——按unicode码点(大写字母在小写字母前) print(sorted(words)) # ['cherry', 'elderberry', 'apple', 'banana', 'date'] # 按字母顺序(忽略大小写) print(sorted(words, key=str.lower)) # ['apple', 'banana', 'cherry', 'date', 'elderberry'] # 按单词长度排序 print(sorted(words, key=len)) # ['date', 'apple', 'banana', 'cherry', 'elderberry']
2.2 key参数的详解
# 💡 key函数的规则:
# 1. key接收一个参数(序列中的每个元素)
# 2. key返回一个用于比较的值
# 3. 排序根据key的返回值进行(不是原始元素)
# 4. 原始元素不变——只是排序的依据变了
# 绝对值排序
numbers = [-5, 3, -1, 4, -2]
print(sorted(numbers, key=abs)) # [-1, -2, 3, 4, -5]
# 按字符串中数字的大小排序
codes = ["item2", "item10", "item1", "item20"]
print(sorted(codes))
# ['item1', 'item10', 'item2', 'item20'] ← 字典序!item10在item2前!
import re
def extract_number(s):
"""提取字符串中的数字"""
match = re.search(r'\d+', s)
return int(match.group()) if match else 0
print(sorted(codes, key=extract_number))
# ['item1', 'item2', 'item10', 'item20'] ← 按数字大小排!
# 按时间排序
times = ["2024-03-15", "2023-12-01", "2024-01-20", "2023-06-10"]
print(sorted(times)) # 字符串比较恰好对日期格式有效!
# ['2023-06-10', '2023-12-01', '2024-01-20', '2024-03-15']
三、lambda作为key——最常用的排序方式
3.1 按字典字段排序
# ⌨️ 排序字典列表——职场中最常用的技能
employees = [
{"name": "张三", "age": 28, "salary": 15000, "department": "技术部"},
{"name": "李四", "age": 35, "salary": 20000, "department": "管理部"},
{"name": "王五", "age": 22, "salary": 12000, "department": "技术部"},
{"name": "赵六", "age": 30, "salary": 18000, "department": "市场部"},
{"name": "钱七", "age": 25, "salary": 13000, "department": "技术部"},
]
# 按年龄排序
by_age = sorted(employees, key=lambda e: e["age"])
print("按年龄:", [e["name"] for e in by_age])
# ['王五', '钱七', '张三', '赵六', '李四']
# 按薪资降序
by_salary = sorted(employees, key=lambda e: e["salary"], reverse=true)
print("按薪资降序:", [(e["name"], e["salary"]) for e in by_salary])
# [('李四', 20000), ('赵六', 18000), ('张三', 15000), ('钱七', 13000), ('王五', 12000)]
# 按年龄排序,同年龄按薪资降序(多级排序)
by_age_salary = sorted(employees, key=lambda e: (e["age"], -e["salary"]))
print("年龄+薪资:", [(e["name"], e["age"], e["salary"]) for e in by_age_salary])
3.2 多级排序
# 💡 多级排序:key返回一个元组
# python按元组的元素顺序依次比较
# 先按部门,再按薪资降序
results = sorted(employees, key=lambda e: (e["department"], -e["salary"]))
for e in results:
print(f" {e['department']} - {e['name']}: ¥{e['salary']}")
# 管理部 - 李四: ¥20000
# 技术部 - 张三: ¥15000
# 技术部 - 钱七: ¥13000
# 技术部 - 王五: ¥12000
# 市场部 - 赵六: ¥18000
# 💡 技巧:降序字段用负号
# 数字降序:-e["salary"](注意:这只对数字有效)
# 字符串降序:没法用负号,需要分两次排序或用functools.cmp_to_key
# 多级排序的另一种方法:多次sorted()(利用稳定性)
# python的排序是稳定的——相同key的元素保持原来的相对顺序
# 先按次要key排,再按主要key排
result = sorted(employees, key=lambda e: e["salary"], reverse=true)
result = sorted(result, key=lambda e: e["department"])
# 结果:同一部门内,按薪资降序
四、高级排序技巧
4.1 使用operator模块
from operator import itemgetter, attrgetter, methodcaller
# itemgetter——获取字典的指定字段(相当于lambda e: e["key"])
# 比lambda稍快一些,而且更简洁
by_department = sorted(employees, key=itemgetter("department"))
print([e["department"] for e in by_department])
# itemgetter多级排序
by_dept_salary = sorted(employees, key=itemgetter("department", "salary"))
# attrgetter——获取对象的属性
class student:
def __init__(self, name, score):
self.name = name
self.score = score
students = [
student("alice", 85),
student("bob", 92),
student("charlie", 78),
]
by_score = sorted(students, key=attrgetter("score"), reverse=true)
for s in by_score:
print(f"{s.name}: {s.score}")
4.2 自定义对象的排序
from functools import total_ordering
# 方法一:实现比较方法
class task:
def __init__(self, name, priority, due_date):
self.name = name
self.priority = priority
self.due_date = due_date
def __lt__(self, other):
"""小于比较:先按priority,再按due_date"""
if self.priority != other.priority:
return self.priority < other.priority
return self.due_date < other.due_date
def __repr__(self):
return f"task({self.name}, pri={self.priority}, due={self.due_date})"
tasks = [
task("写报告", 2, "2024-06-15"),
task("修复bug", 1, "2024-06-10"),
task("开会", 2, "2024-06-12"),
task("代码审查", 1, "2024-06-08"),
]
print(sorted(tasks))
# [task(代码审查, pri=1, due=2024-06-08), task(修复bug, pri=1, due=2024-06-10),
# task(开会, pri=2, due=2024-06-12), task(写报告, pri=2, due=2024-06-15)]
# 方法二:使用key(更灵活,不修改类)
tasks_sorted = sorted(tasks, key=lambda t: (t.priority, t.due_date))
五、实战案例
5.1 日志按时间排序
# 场景:排序杂乱的日志条目
logs = [
"[2024-03-15 14:30:22] error 数据库连接失败",
"[2024-03-15 14:25:10] info 服务器启动",
"[2024-03-15 14:32:05] warning 内存使用率85%",
"[2024-03-15 14:25:10] debug 加载配置文件",
"[2024-03-15 14:28:45] info 用户登录成功",
]
def extract_timestamp(log_line):
"""从日志行中提取时间戳"""
return log_line[1:20] # 提取 "[2024-03-15 14:30:22]" 中的时间
sorted_logs = sorted(logs, key=extract_timestamp)
for log in sorted_logs:
print(log)
# 按时间正序排列
# 对于同时间的日志,按级别排序
level_priority = {"debug": 0, "info": 1, "warning": 2, "error": 3}
def sort_key(log_line):
timestamp = extract_timestamp(log_line)
# 提取日志级别
level = log_line[22:].split()[0]
priority = level_priority.get(level, 99)
return (timestamp, priority)
sorted_logs = sorted(logs, key=sort_key)
5.2 自然排序
import re
# 人类期望的排序(自然排序):file1, file2, ..., file10, file11
# 而不是字典序:file1, file10, file11, file2, ...
def natural_sort_key(s):
"""自然排序的key函数"""
# 将字符串分割为文本和数字的交替序列
parts = re.split(r'(\d+)', s)
# 将数字部分转为整数
return [int(part) if part.isdigit() else part.lower() for part in parts]
files = ["file10.txt", "file1.txt", "file2.txt", "file20.txt", "file11.txt"]
print(sorted(files))
# ['file1.txt', 'file10.txt', 'file11.txt', 'file2.txt', 'file20.txt'] ← 字典序
print(sorted(files, key=natural_sort_key))
# ['file1.txt', 'file2.txt', 'file10.txt', 'file11.txt', 'file20.txt'] ← 自然序
六、总结
sorted()的key参数是python排序系统的精髓,它让你能按任意规则排序——从简单的按长度排,到复杂的多字段组合排序。
💡 核心要点:
sorted()返回新列表,list.sort()原地排序key函数定义排序依据——返回什么就按什么排- 元组key实现多级排序——
key=lambda x: (x.a, -x.b) - 稳定性——两次sorted可实现复杂排序
- lambda + key是最常用的排序方式
✅ 记住:key返回的不是元素本身,而是用于比较的"排序值"。合理使用key,你能排序任何数据结构。
到此这篇关于python中sorted()排序函数与自定义排序规则的文章就介绍到这了,更多相关python中sorted()排序与自定义排序内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论