Python列表排序:sorted与sort详解
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《Python列表排序:sorted与sort方法全解析》,聊聊,我们一起来看看吧!
Python中列表排序主要用list.sort()和sorted(),前者原地修改列表并返回None,后者返回新列表不改变原列表;选择取决于是否需保留原顺序,结合key参数可实现灵活排序,且Python排序稳定,适用于复杂数据类型。
Python中对列表进行排序主要有两种核心方法:list.sort()
方法和内置的 sorted()
函数。简单来说,list.sort()
会直接修改原列表,原地完成排序,而 sorted()
函数则会返回一个新的已排序列表,保持原列表不变。选择哪一个取决于你是否需要保留原始列表的顺序。
解决方案
在Python中,对列表进行排序是日常编程中非常常见的操作,无论是处理用户输入、数据分析还是算法实现,排序都扮演着重要角色。理解 list.sort()
和 sorted()
这两个工具的细微差别和各自的适用场景,是高效编写Python代码的关键。
1. list.sort()
方法
list.sort()
是列表对象的一个方法,它会直接在原地(in-place)修改列表,将其元素进行排序。这意味着调用后,原列表的内容就变成了排序后的结果,并且这个方法没有返回值(它返回 None
)。
语法:list.sort(key=None, reverse=False)
key
: (可选)一个函数,用于从每个列表元素中提取一个比较键。这个键将用于实际的比较操作。默认情况下,元素本身用于比较。reverse
: (可选)一个布尔值。如果设置为True
,列表将以降序(从大到小)排列;默认为False
,即升序排列。
示例:
numbers = [3, 1, 4, 1, 5, 9, 2, 6] print(f"原始列表: {numbers}") numbers.sort() # 默认升序排序 print(f"使用 sort() 升序排序后: {numbers}") numbers_desc = [3, 1, 4, 1, 5, 9, 2, 6] numbers_desc.sort(reverse=True) # 降序排序 print(f"使用 sort() 降序排序后: {numbers_desc}") words = ["banana", "Apple", "cherry", "Date"] words.sort(key=str.lower) # 忽略大小写排序 print(f"使用 sort() 忽略大小写排序后: {words}")
2. sorted()
函数
sorted()
是Python的内置函数,它可以接受任何可迭代对象(不仅仅是列表),并返回一个新的、已排序的列表。原始的可迭代对象不会被修改。
语法:sorted(iterable, key=None, reverse=False)
iterable
: 任何可迭代对象(如列表、元组、字符串、字典的键等)。key
: (可选)与list.sort()
中的key
参数相同。reverse
: (可选)与list.sort()
中的reverse
参数相同。
示例:
data = (5, 2, 8, 1, 9) # 一个元组 print(f"原始元组: {data}") sorted_list = sorted(data) # 返回一个新的列表 print(f"使用 sorted() 排序后的列表: {sorted_list}") print(f"原始元组保持不变: {data}") names = ["Charlie", "alice", "Bob"] sorted_names = sorted(names, key=str.lower, reverse=True) # 忽略大小写降序 print(f"使用 sorted() 忽略大小写降序排序后的列表: {sorted_names}") print(f"原始列表保持不变: {names}")
Python列表排序时,何时选择 sort()
而非 sorted()
?
选择 list.sort()
还是 sorted()
,这其实是一个关于“副作用”和“内存管理”的权衡。我个人在编码时,如果确定不需要保留原始列表的状态,并且列表可能非常大,我会倾向于使用 list.sort()
。这不完全是出于性能上的极致追求,更多时候是考虑到代码的意图和资源的合理利用。
list.sort()
的主要优势在于:
- 内存效率: 当处理非常大的列表时,
list.sort()
由于是原地修改,不需要额外创建新的列表对象来存储排序结果。这意味着它在内存使用上更加高效。如果你的程序对内存占用敏感,或者列表的复制成本很高,sort()
是一个更好的选择。 - 性能略优: 通常情况下,原地排序会比创建一个新列表并填充它要快一些,因为它避免了新列表对象的创建和垃圾回收的开销。对于小列表,这种差异可以忽略不计,但对于百万级甚至千万级的列表,累积起来的性能提升就值得考虑了。
- 明确的意图: 当你明确知道你不再需要列表的原始顺序,并且希望它直接变成排序后的状态时,使用
sort()
可以更清晰地表达这种意图。这在一些数据预处理流程中很常见,比如你从数据库取出一批记录,然后直接对其进行排序以供后续处理,原顺序已经不重要了。
举个例子,假设你正在编写一个游戏,需要对一个包含数千个敌人的列表进行排序,以便找出最近的几个敌人。如果你每次都用 sorted()
创建一个新列表,那么在每一帧(或每次需要排序时),都会产生大量的临时列表对象,这可能会给垃圾回收器带来压力,甚至导致帧率下降。在这种情况下,直接对敌人列表进行 sort()
可能是更明智的选择。当然,这只是一个场景,实际情况要具体分析。
key
参数在Python列表排序中的高级用法是什么?
key
参数是Python排序功能中的一个“瑞士军刀”,它极大地扩展了排序的灵活性和表达力。它允许你定义一个函数,这个函数会在每个元素被比较之前被调用,并返回一个值。真正用于排序比较的,是这个函数的返回值,而不是元素本身。这使得我们可以根据元素的任何属性、计算结果甚至是复杂逻辑来排序。
以下是一些 key
参数的高级用法示例:
根据对象属性排序: 当你有一个自定义对象列表时,
key
参数非常有用。class Product: def __init__(self, name, price, stock): self.name = name self.price = price self.stock = stock def __repr__(self): # 便于打印 return f"Product('{self.name}', ${self.price}, {self.stock} units)" products = [ Product("Laptop", 1200, 50), Product("Mouse", 25, 200), Product("Keyboard", 75, 100), Product("Monitor", 300, 30) ] # 根据价格升序排序 sorted_by_price = sorted(products, key=lambda p: p.price) print("按价格排序:", sorted_by_price) # 根据库存降序排序 sorted_by_stock_desc = sorted(products, key=lambda p: p.stock, reverse=True) print("按库存降序排序:", sorted_by_stock_desc)
根据元组或列表的特定索引排序: 当列表包含元组或子列表时,你可以根据其中某个元素进行排序。
students = [ ("Alice", 20, "A"), ("Bob", 22, "C"), ("Charlie", 20, "B"), ("David", 21, "A") ] # 根据年龄排序 sorted_by_age = sorted(students, key=lambda s: s[1]) print("按年龄排序:", sorted_by_age) # 结合 operator.itemgetter 进行多级排序(更高效) from operator import itemgetter # 先按年龄,再按成绩(成绩A > B > C) # 注意:这里成绩是字符串,直接比较是按字母顺序,如果需要自定义成绩等级,key函数会更复杂 sorted_by_age_then_grade = sorted(students, key=itemgetter(1, 2)) print("按年龄再按成绩排序:", sorted_by_age_then_grade)
自定义复杂排序逻辑:
key
函数可以包含任何你想要的复杂逻辑。file_names = ["img10.png", "img2.png", "img1.png", "img100.png"] # 按照文件名中的数字部分进行排序 (例如 img1.png, img2.png, img10.png, img100.png) import re def natural_sort_key(s): # 提取数字部分并转换为整数,非数字部分保持字符串 return [int(text) if text.isdigit() else text.lower() for text in re.split('([0-9]+)', s)] sorted_files = sorted(file_names, key=natural_sort_key) print("自然排序文件:", sorted_files)
这个
natural_sort_key
函数就是一个很好的例子,它使得原本按字典序排序会出错的字符串("img10" 在 "img2" 之前)能够按照我们人类的直觉进行排序。key
参数的强大之处在于,它将“如何比较”的细节封装起来,让排序接口保持简洁。
如何处理Python列表排序中的稳定性问题和复杂数据类型?
在Python中处理列表排序,除了知道如何用 sort()
和 sorted()
,理解“稳定性”以及如何应对“复杂数据类型”是进阶的关键。这些点,在我看来,是区分一个熟练的Python开发者和初学者的重要标志。
1. 排序稳定性(Stability)
Python的内置排序算法(Timsort,它是归并排序和插入排序的混合体)是稳定的。这意味着如果两个元素在排序时具有相同的键(或者说,它们在比较时被认为是相等的),那么它们在排序后的列表中会保持它们在原始列表中的相对顺序。
为什么稳定性很重要? 考虑一个场景:你有一份学生名单,每个学生有姓名和分数。
- 你首先按姓名首字母排序。
- 然后,你希望按分数降序排序,但对于分数相同的学生,你希望他们保持原先按姓名排序的顺序。
如果排序算法不稳定,第二次按分数排序可能会打乱第一次按姓名排序的相对顺序。但因为Python的排序是稳定的,你可以先按次要标准排序,再按主要标准排序,就能达到多级排序的效果。
示例:
data = [('apple', 3), ('banana', 1), ('cherry', 3), ('date', 2)] # 先按字母顺序排序(次要标准) sorted_by_name = sorted(data, key=lambda x: x[0]) print("按名称排序:", sorted_by_name) # 输出: [('apple', 3), ('banana', 1), ('cherry', 3), ('date', 2)] # 再按数字降序排序(主要标准),注意稳定性 # 对于数字相同的元素,它们在 sorted_by_name 中的相对顺序会被保留 final_sorted = sorted(sorted_by_name, key=lambda x: x[1], reverse=True) print("先按名称再按数字降序排序:", final_sorted) # 输出: [('apple', 3), ('cherry', 3), ('date', 2), ('banana', 1)] # 注意 'apple' 和 'cherry' 都是3,它们在最终结果中仍然保持了 'apple' 在 'cherry' 之前的顺序,这就是稳定性。
在实际项目中,多级排序的需求很常见,理解稳定性可以让你更自信地构建复杂的排序逻辑。
2. 复杂数据类型的排序
当列表中的元素不是简单的数字或字符串,而是自定义对象、混合类型元组等复杂数据类型时,直接排序可能会遇到问题,或者需要更精细的控制。
自定义对象: 如果你有一个自定义类的实例列表,直接调用
sorted()
或list.sort()
而不提供key
参数,Python可能会抛出TypeError
,因为默认情况下它不知道如何比较你的对象。解决方案1:使用
key
参数(最常用、最灵活) 正如前面所述,通过key
参数提供一个函数,告诉Python如何从每个对象中提取一个可比较的值。这是处理自定义对象排序的首选方法,因为它不修改类的定义,可以在不同场景下提供不同的排序逻辑。解决方案2:实现
__lt__
方法(定义对象的自然顺序) 如果你希望你的自定义对象能够“自然地”排序,即它们有一个默认的、固定的比较逻辑,你可以在类中实现__lt__
(less than) 魔术方法。当Python需要比较两个对象时,如果它们没有提供key
参数,就会尝试调用这个方法。class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"Person('{self.name}', {self.age})" # 定义小于操作符,使得 Person 对象可以根据年龄进行比较 def __lt__(self, other): if not isinstance(other, Person): return NotImplemented return self.age < other.age people = [Person('Alice', 30), Person('Bob', 25), Person('Charlie', 30)] # 现在可以直接排序,因为 Person 类定义了 __lt__ sorted_people = sorted(people) print("按年龄自然排序:", sorted_people) # 仍然可以使用 key 参数覆盖默认行为,例如按姓名排序 sorted_by_name = sorted(people, key=lambda p: p.name) print("按姓名排序:", sorted_by_name)
实现
__lt__
方法,可以让你的对象在很多Python内置函数和数据结构中(例如min()
,max()
,heapq
模块)也能够自然地工作,这是一种更深层次的集成。混合类型列表: Python 3 默认不允许对不同类型的元素进行比较(例如,
1 < 'a'
会抛出TypeError
)。如果你的列表中包含混合类型,并且需要排序,你必须提供一个key
函数来将所有元素转换为可比较的类型,或者处理这些类型差异。mixed_list = [5, "apple", 2, "banana", 10] # 这会报错:TypeError: '<' not supported between instances of 'str' and 'int' # sorted_mixed = sorted(mixed_list) # 解决方案:使用 key 函数,将所有元素转换为字符串进行比较 sorted_mixed_str = sorted(mixed_list, key=str) print("混合类型按字符串排序:", sorted_mixed_str) # 输出: [10, 2, 5, 'apple', 'banana'] # 或者,更复杂的逻辑,例如先按类型分组,再在组内排序 def custom_mixed_sort_key(item): if isinstance(item, int): return (0, item) # 数字排在前面 elif isinstance(item, str): return (1, item) # 字符串排在后面 return (2, str(item)) # 其他类型 sorted_mixed_custom = sorted(mixed_list, key=custom_mixed_sort_key) print("混合类型自定义排序:", sorted_mixed_custom) # 输出: [2, 5, 10, 'apple', 'banana']
处理复杂数据类型时,关键在于清晰地定义你希望的比较逻辑。
key
参数和__lt__
方法为你提供了强大的工具来表达这些逻辑,让排序行为符合你的预期。
好了,本文到此结束,带大家了解了《Python列表排序:sorted与sort详解》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!

- 上一篇
- 京东医院app实用吗?功能服务全面测评

- 下一篇
- JavaScript处理大数据前端展示技巧
-
- 文章 · python教程 | 7分钟前 |
- Pandas添加子串分类列技巧
- 330浏览 收藏
-
- 文章 · python教程 | 16分钟前 |
- Pandas合并教程:部分匹配详解
- 271浏览 收藏
-
- 文章 · python教程 | 24分钟前 |
- Python获取文件绝对路径方法
- 107浏览 收藏
-
- 文章 · python教程 | 29分钟前 |
- Python三种常见注释方式解析
- 418浏览 收藏
-
- 文章 · python教程 | 45分钟前 |
- PythonWeb开发入门:Django框架教程
- 412浏览 收藏
-
- 文章 · python教程 | 49分钟前 |
- Python列表操作与斐波那契生成方法
- 389浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python数据挖掘:sklearn算法实战解析
- 229浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python动态属性类型提示技巧分享
- 325浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python生成器是什么?详解原理与用法
- 125浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- WisPaper
- WisPaper是复旦大学团队研发的智能科研助手,提供AI文献精准搜索、智能翻译与核心总结功能,助您高效搜读海量学术文献,全面提升科研效率。
- 92次使用
-
- Canva可画-AI简历生成器
- 探索Canva可画AI简历生成器,融合AI智能分析、润色与多语言翻译,提供海量专业模板及个性化设计。助您高效创建独特简历,轻松应对各类求职挑战,提升成功率。
- 110次使用
-
- 潮际好麦-AI试衣
- 潮际好麦 AI 试衣平台,助力电商营销、设计领域,提供静态试衣图、动态试衣视频等全方位服务,高效打造高质量商品展示素材。
- 195次使用
-
- 蝉妈妈AI
- 蝉妈妈AI是国内首个聚焦电商领域的垂直大模型应用,深度融合独家电商数据库与DeepSeek-R1大模型。作为电商人专属智能助手,它重构电商运营全链路,助力抖音等内容电商商家实现数据分析、策略生成、内容创作与效果优化,平均提升GMV 230%,是您降本增效、抢占增长先机的关键。
- 394次使用
-
- 数说Social Research-社媒分析AI Agent
- 数说Social Research是数说故事旗下社媒智能研究平台,依托AI Social Power,提供全域社媒数据采集、垂直大模型分析及行业场景化应用,助力品牌实现“数据-洞察-决策”全链路支持。
- 256次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览