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

1 阅读8分钟

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

灵活、高效的数据排序

前言

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

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

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


一、排序基础

1.1 基本语法

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

1.2 基本示例

# 数字排序
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 按绝对值排序

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 按字符串长度排序

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排序的问题

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 函数:

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 对元组列表排序

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 对字典列表排序

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 表达式简化

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 更快:

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 多级排序

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

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),可以转换:

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 对字典按值排序

# 统计单词出现次数
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 对文件列表排序

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 排序并去重

# 方法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 快
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) 返回新列表
自定义keykey 参数指定排序依据函数
降序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」


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