Python高级特性:sorted() 排序完全指南

Python高级特性:sorted() 排序完全指南

灵活、高效的数据排序

前言

排序是编程中最常用的操作之一。Python 提供了内置的 sorted() 函数,可以对各种可迭代对象进行排序。与列表的 sort() 方法不同,sorted()返回一个新列表,原对象保持不变。

本文将系统讲解 sorted() 的基本用法、自定义排序规则、复杂对象排序、多级排序以及性能优化技巧,帮助你掌握Python中强大的排序功能。

📚 本文内容基于道满PythonAI - 排序教程


一、排序基础

1.1 基本语法

python 复制代码
sorted(iterable, key=None, reverse=False)
参数 说明
iterable 可迭代对象(列表、元组、字符串等)
key 可选,指定排序依据的函数
reverse 可选,True为降序,False为升序(默认)
返回值 新的排序后的列表

1.2 基本示例

python 复制代码
# 数字排序
numbers = [36, 5, -12, 9, -21]
sorted_numbers = sorted(numbers)
print(sorted_numbers)  # [-21, -12, 5, 9, 36]
print(numbers)         # [36, 5, -12, 9, -21] 原列表不变

# 字符串排序(按ASCII码)
words = ['banana', 'apple', 'Cherry', 'date']
print(sorted(words))   # ['Cherry', 'apple', 'banana', 'date']
# 注意:大写字母排在小写字母前面(ASCII码中'A'=65, 'a'=97)

二、自定义排序:key 参数

sorted() 是一个高阶函数 ,可以接收 key 参数来自定义排序规则。key 函数会应用于每个元素,然后根据返回的结果进行排序。

2.1 按绝对值排序

python 复制代码
numbers = [36, 5, -12, 9, -21]

# 按绝对值排序
sorted_by_abs = sorted(numbers, key=abs)
print(sorted_by_abs)  # [5, 9, -12, -21, 36]

# 计算过程:
# abs(36)=36, abs(5)=5, abs(-12)=12, abs(9)=9, abs(-21)=21
# 按[36,5,12,9,21]排序 → [5,9,12,21,36]
# 对应原值 → [5, 9, -12, -21, 36]

2.2 按字符串长度排序

python 复制代码
words = ['python', 'is', 'awesome', 'and', 'powerful']

# 按长度升序
sorted_by_len = sorted(words, key=len)
print(sorted_by_len)  
# ['is', 'and', 'python', 'awesome', 'powerful']

# 按长度降序
sorted_by_len_desc = sorted(words, key=len, reverse=True)
print(sorted_by_len_desc)
# ['awesome', 'powerful', 'python', 'and', 'is']

三、字符串排序与大小写处理

3.1 默认ASCII排序的问题

python 复制代码
words = ['bob', 'about', 'Zoo', 'Credit']

# 默认排序(按ASCII码)
print(sorted(words))  
# ['Credit', 'Zoo', 'about', 'bob']
# 因为 'C' (67) < 'Z' (90) < 'a' (97) < 'b' (98)

3.2 忽略大小写排序

使用 str.lowerstr.upper 作为 key 函数:

python 复制代码
words = ['bob', 'about', 'Zoo', 'Credit']

# 忽略大小写排序
sorted_ignore_case = sorted(words, key=str.lower)
print(sorted_ignore_case)  
# ['about', 'bob', 'Credit', 'Zoo']

# 降序
sorted_desc = sorted(words, key=str.lower, reverse=True)
print(sorted_desc)  
# ['Zoo', 'Credit', 'bob', 'about']

四、复杂对象排序

4.1 对元组列表排序

python 复制代码
students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

# 方法1:定义普通函数
def by_name(t):
    return t[0].lower()  # 按名字(忽略大小写)

def by_score(t):
    return t[1]          # 按成绩

# 按名字升序
sorted_by_name = sorted(students, key=by_name)
print(sorted_by_name)
# [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]

# 按成绩升序
sorted_by_score = sorted(students, key=by_score)
print(sorted_by_score)
# [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]

# 按成绩降序(使用负数)
def by_score_desc(t):
    return -t[1]

sorted_by_score_desc = sorted(students, key=by_score_desc)
print(sorted_by_score_desc)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

4.2 对字典列表排序

python 复制代码
students_dict = [
    {'name': 'Bob', 'score': 75},
    {'name': 'Adam', 'score': 92},
    {'name': 'Bart', 'score': 66},
    {'name': 'Lisa', 'score': 88}
]

# 按score排序
sorted_by_score = sorted(students_dict, key=lambda x: x['score'])
print(sorted_by_score)
# [{'name': 'Bart', 'score': 66}, {'name': 'Bob', 'score': 75}, 
#  {'name': 'Lisa', 'score': 88}, {'name': 'Adam', 'score': 92}]

# 按name排序(忽略大小写)
sorted_by_name = sorted(students_dict, key=lambda x: x['name'].lower())
print(sorted_by_name)
# [{'name': 'Adam', 'score': 92}, {'name': 'Bart', 'score': 66}, 
#  {'name': 'Bob', 'score': 75}, {'name': 'Lisa', 'score': 88}]

五、现代Python排序技巧

5.1 使用 lambda 表达式简化

python 复制代码
students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

# 按名字排序
sorted_by_name = sorted(students, key=lambda x: x[0].lower())

# 按成绩降序
sorted_by_score = sorted(students, key=lambda x: -x[1])

print(sorted_by_name)   # [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
print(sorted_by_score)  # [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

5.2 使用 operator 模块提高效率

operator 模块提供了 itemgetterattrgetter,比 lambda 更快:

python 复制代码
from operator import itemgetter, attrgetter

students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

# 按名字排序
sorted_by_name = sorted(students, key=itemgetter(0))
print(sorted_by_name)
# [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]

# 按成绩排序(降序)
sorted_by_score = sorted(students, key=itemgetter(1), reverse=True)
print(sorted_by_score)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

# 对于对象列表,使用attrgetter
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

students_obj = [Student('Bob', 75), Student('Adam', 92), Student('Bart', 66)]

sorted_by_name = sorted(students_obj, key=attrgetter('name'))
print([s.name for s in sorted_by_name])  # ['Adam', 'Bart', 'Bob']

5.3 多级排序

先按成绩降序,成绩相同再按名字升序:

python 复制代码
students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88), ('Eve', 75)]

# 方法1:使用lambda返回元组
sorted_multi = sorted(students, key=lambda x: (-x[1], x[0].lower()))
print(sorted_multi)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Eve', 75), ('Bart', 66)]

# 方法2:多次排序(Python的排序是稳定的)
# 先按名字升序,再按成绩降序
step1 = sorted(students, key=lambda x: x[0].lower())  # 按名字
step2 = sorted(step1, key=lambda x: x[1], reverse=True)  # 再按成绩
print(step2)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Eve', 75), ('Bart', 66)]

# 说明:稳定排序保证相同成绩时,名字的顺序保持第一次排序的结果

5.4 使用 functools.cmp_to_key(兼容旧式比较函数)

如果你有老式的比较函数(返回-1/0/1),可以转换:

python 复制代码
from functools import cmp_to_key

def compare(a, b):
    """自定义比较函数:按成绩降序,成绩相同按名字升序"""
    if a[1] != b[1]:
        return b[1] - a[1]  # 成绩高的排前面
    else:
        if a[0].lower() < b[0].lower():
            return -1
        elif a[0].lower() > b[0].lower():
            return 1
        return 0

students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88), ('Eve', 75)]
sorted_custom = sorted(students, key=cmp_to_key(compare))
print(sorted_custom)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Eve', 75), ('Bart', 66)]

六、实战案例

6.1 对字典按值排序

python 复制代码
# 统计单词出现次数
word_counts = {'apple': 5, 'banana': 3, 'cherry': 8, 'date': 3}

# 按值升序
sorted_by_value = sorted(word_counts.items(), key=lambda x: x[1])
print(sorted_by_value)
# [('banana', 3), ('date', 3), ('apple', 5), ('cherry', 8)]

# 按值降序
sorted_by_value_desc = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)
print(sorted_by_value_desc)
# [('cherry', 8), ('apple', 5), ('banana', 3), ('date', 3)]

# 先按值降序,值相同按键升序
sorted_multi = sorted(word_counts.items(), key=lambda x: (-x[1], x[0]))
print(sorted_multi)
# [('cherry', 8), ('apple', 5), ('banana', 3), ('date', 3)]

6.2 对文件列表排序

python 复制代码
import os
from operator import attrgetter

# 获取当前目录下的文件信息
files = [os.path.join('.', f) for f in os.listdir('.') if os.path.isfile(f)]
file_infos = [(f, os.path.getsize(f), os.path.getmtime(f)) for f in files]

# 按文件大小排序
by_size = sorted(file_infos, key=lambda x: x[1])
print("按大小排序(最小在前):")
for name, size, _ in by_size[:3]:
    print(f"  {name}: {size} bytes")

# 按修改时间排序(最新在前)
by_time = sorted(file_infos, key=lambda x: x[2], reverse=True)
print("\n按修改时间排序(最新在前):")
for name, _, mtime in by_time[:3]:
    print(f"  {name}: {time.ctime(mtime)}")

6.3 排序并去重

python 复制代码
# 方法1:使用sorted(set())
numbers = [5, 2, 8, 2, 1, 5, 9, 8]
unique_sorted = sorted(set(numbers))
print(unique_sorted)  # [1, 2, 5, 8, 9]

# 方法2:使用dict.fromkeys()保持首次出现顺序(Python 3.7+)
unique_ordered = list(dict.fromkeys(numbers))
print(unique_ordered)  # [5, 2, 8, 1, 9]

七、性能考虑

方法 时间复杂度 说明
sorted() O(n log n) Timsort算法,稳定排序
list.sort() O(n log n) 原地排序,更省内存
key函数 O(n) 每个元素调用一次,缓存结果

性能优化建议

  1. key函数应尽量简单:复杂函数会拖慢排序
  2. 避免在key中使用lambda调用慢速函数:可以预先计算
  3. 对于大数据集,使用 operator.itemgetter 比 lambda 快
python 复制代码
import timeit

students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] * 1000

# lambda方式
def sort_lambda():
    return sorted(students, key=lambda x: x[1])

# itemgetter方式(更快)
from operator import itemgetter
def sort_itemgetter():
    return sorted(students, key=itemgetter(1))

# 性能测试(在实际环境中运行)
# print(timeit.timeit(sort_lambda, number=1000))
# print(timeit.timeit(sort_itemgetter, number=1000))

八、总结

知识点 要点
基本排序 sorted(iterable) 返回新列表
自定义key key 参数指定排序依据函数
降序 reverse=True
忽略大小写 key=str.lower
元组/字典排序 key=lambda x: x[0]itemgetter
多级排序 key=lambda x: (-x[1], x[0])
稳定排序 相等元素保持原顺序
性能优化 使用 itemgetter,简化key函数

核心要点

  1. sorted() 返回新列表,原对象不变
  2. key 参数是高阶函数的核心,可以自定义排序规则
  3. ✅ 字符串排序注意大小写,使用 str.lower 忽略大小写
  4. ✅ 多级排序通过返回元组实现
  5. operator.itemgetter 比 lambda 更高效
  6. ✅ Python的排序是稳定的,可以链式排序实现复杂逻辑

掌握 sorted() 函数,可以让你轻松应对各种排序需求,写出简洁高效的代码。


📚 相关推荐阅读


💡 Python 学习不走弯路!

体系化实战路线:基础语法 · 异步Web开发 · 数据采集 · 计算机视觉 · NLP · 大模型RAG实战

------ 全在 「道满PythonAI」


如果这篇文章对你有帮助,欢迎点赞、评论、收藏,你的支持是我持续分享的动力!🎉

相关推荐
Henrii_历小海4 分钟前
WhatsApp Web 不是手机镜像:多设备协议、本地数据流与出海获客流水线
前端·智能手机
ayqy贾杰11 分钟前
Claude Fable 5 提示词泄漏,抓紧学习下
前端·后端·面试
智码看视界17 分钟前
Day18 SpringBoot自动配置原理:从@SpringBootApplication开始
java·spring boot·后端·自动装配
程序员爱钓鱼31 分钟前
Rust 常量与静态变量详解:const 与 static 的区别
后端
To_OC8 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic9 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy9 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志9 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble10 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯11 小时前
管理是否可以被完全量化
前端·产品经理·团队管理