python怎么对列表进行排序_python列表排序方法详解

尼克
发布: 2025-09-21 23:28:01
原创
582人浏览过
Python列表排序有两种方法:list.sort()原地修改列表并返回None,适用于无需保留原列表的场景;sorted()函数返回新列表,不改变原始数据,适合需保留原序或处理不可变对象的情况。两者均使用稳定的Timsort算法,默认升序排列,支持通过key参数自定义排序规则(如按长度、属性或字典值),reverse=True可实现降序。选择取决于是否需保留原列表及内存使用考量,性能差异主要体现在sorted()有额外的内存开销。

python怎么对列表进行排序_python列表排序方法详解

Python对列表进行排序主要有两种核心方法:一种是列表对象自带的

sort()
登录后复制
方法,它会直接修改原列表;另一种是内置的
sorted()
登录后复制
函数,它会返回一个新的已排序列表,而不会改变原始列表。选择哪种方式,关键在于你是否需要保留原列表的原始顺序。

解决方案

要对Python列表进行排序,最直接有效的方式就是利用其内建的排序机制。这两种机制各有侧重,但都提供了强大的自定义能力。

list.sort()
登录后复制
方法是列表对象的一个方法,它会原地(in-place)修改列表内容,将其元素重新排列为有序状态。这意味着调用这个方法后,原列表的顺序就变了,并且这个方法本身没有返回值(它返回
None
登录后复制
)。如果你不需要保留原始列表,并且追求一点点性能上的优势(因为它不需要创建新的列表对象),那么
sort()
登录后复制
是个不错的选择。

my_list = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"原始列表: {my_list}") # 原始列表: [3, 1, 4, 1, 5, 9, 2, 6]
my_list.sort()
print(f"使用sort()后: {my_list}") # 使用sort()后: [1, 1, 2, 3, 4, 5, 6, 9]

# 降序排序
another_list = [8, 0, 7, 2, 5]
another_list.sort(reverse=True)
print(f"降序排序后: {another_list}") # 降序排序后: [8, 7, 5, 2, 0]
登录后复制

sorted()
登录后复制
函数是一个内置函数,它的优势在于可以接受任何可迭代对象(不限于列表)作为参数,并返回一个全新的、已排序的列表。原始的可迭代对象不会受到任何影响。这在很多场景下非常有用,比如你需要基于一个列表生成多个不同排序方式的视图,或者你正在处理一个元组、集合等不可变类型,又或者你仅仅想获取一个排序后的结果而不碰原始数据。

立即学习Python免费学习笔记(深入)”;

original_data = [('apple', 3), ('banana', 1), ('cherry', 2)]
print(f"原始数据: {original_data}") # 原始数据: [('apple', 3), ('banana', 1), ('cherry', 2)]

# 默认排序(按元组的第一个元素)
sorted_data = sorted(original_data)
print(f"使用sorted()后: {sorted_data}") # 使用sorted()后: [('apple', 3), ('banana', 1), ('cherry', 2)]

# 降序排序
reverse_sorted_data = sorted(original_data, reverse=True)
print(f"使用sorted()降序后: {reverse_sorted_data}") # 使用sorted()降序后: [('cherry', 2), ('banana', 1), ('apple', 3)]

# 原始数据未改变
print(f"原始数据依然: {original_data}") # 原始数据依然: [('apple', 3), ('banana', 1), ('cherry', 2)]
登录后复制

无论是

sort()
登录后复制
还是
sorted()
登录后复制
,它们都支持
key
登录后复制
reverse
登录后复制
这两个参数,这让排序的灵活性大大提升。

Python列表排序时,如何自定义排序规则?
key
登录后复制
参数有什么用?

在Python中,如果只是简单地对数字或字符串进行升序或降序排列,默认行为通常就够用了。但现实世界的数据往往更复杂,比如你可能有一堆学生对象,需要按年龄排序,或者一堆文件名,需要按文件大小排序。这时候,

key
登录后复制
参数就成了你的“魔法棒”,它允许你定义一个函数,这个函数会在排序时作用于列表中的每个元素,然后用这个函数的返回值来作为实际的比较依据。

key
登录后复制
参数接受一个单参数函数,这个函数会为列表中的每个元素生成一个“排序键”。排序算法实际上比较的是这些键,而不是元素本身。我个人觉得,
key
登录后复制
参数是Python排序功能里最强大也最灵活的设计之一,它把排序的“决策权”交给了开发者,而不是强行规定一套规则。

举几个例子来说明:

按字符串长度排序:

假设你有一个字符串列表,想根据每个字符串的长度来排序,而不是按字母顺序。

words = ["apple", "banana", "kiwi", "grapefruit", "cat"]
# 默认排序是按字母顺序
print(f"默认排序: {sorted(words)}") # 默认排序: ['apple', 'banana', 'cat', 'grapefruit', 'kiwi']

# 按长度排序
print(f"按长度排序: {sorted(words, key=len)}") # 按长度排序: ['cat', 'kiwi', 'apple', 'banana', 'grapefruit']
登录后复制

这里

len
登录后复制
函数就是
key
登录后复制
参数的值,它会返回每个字符串的长度,然后
sorted()
登录后复制
函数就根据这些长度值进行排序。

按自定义对象属性排序:

如果你有一个自定义类的实例列表,比如学生对象,每个学生有姓名和分数。

class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __repr__(self): # 为了方便打印
        return f"Student({self.name}, {self.score})"

students = [
    Student("Alice", 90),
    Student("Bob", 85),
    Student("Charlie", 92),
    Student("David", 85)
]

# 按分数排序
# 这里使用lambda函数,它是一个匿名函数,用于快速定义一个简单的key
sorted_by_score = sorted(students, key=lambda student: student.score)
print(f"按分数排序: {sorted_by_score}")
# 输出: [Student(Bob, 85), Student(David, 85), Student(Alice, 90), Student(Charlie, 92)]

# 如果分数相同,我们可能还想按姓名排序。这就涉及多级排序,但`key`只处理一级。
# 要实现多级排序,可以返回一个元组作为key,Python会按元组元素的顺序进行比较
sorted_by_score_then_name = sorted(students, key=lambda student: (student.score, student.name))
print(f"按分数再按姓名排序: {sorted_by_score_then_name}")
# 输出: [Student(Bob, 85), Student(David, 85), Student(Alice, 90), Student(Charlie, 92)]
# 注意:这里Bob和David分数相同,但Bob在David之前,因为'B'在'D'之前。
登录后复制

通过

lambda student: student.score
登录后复制
,我们告诉排序函数,用每个学生的
score
登录后复制
属性作为比较的依据。而
lambda student: (student.score, student.name)
登录后复制
则实现了先按分数,分数相同再按姓名的多级排序。

按字典中的特定键值排序:

data = [
    {'name': 'John', 'age': 30, 'city': 'New York'},
    {'name': 'Jane', 'age': 25, 'city': 'London'},
    {'name': 'Mike', 'age': 35, 'city': 'Paris'}
]

# 按年龄排序
sorted_by_age = sorted(data, key=lambda item: item['age'])
print(f"按年龄排序: {sorted_by_age}")
# 输出: [{'name': 'Jane', 'age': 25, 'city': 'London'}, {'name': 'John', 'age': 30, 'city': 'New York'}, {'name': 'Mike', 'age': 35, 'city': 'Paris'}]
登录后复制

key
登录后复制
参数的灵活性让Python的排序功能几乎可以应对所有自定义排序的需求,是处理复杂数据结构排序时不可或缺的工具

序列猴子开放平台
序列猴子开放平台

具有长序列、多模态、单模型、大数据等特点的超大规模语言模型

序列猴子开放平台 0
查看详情 序列猴子开放平台

Python列表排序是升序还是降序?排序算法是稳定的吗?

关于Python列表的排序方向,默认情况下,无论是

list.sort()
登录后复制
还是
sorted()
登录后复制
函数,它们都会执行升序排序。这意味着数字从小到大,字符串按字母顺序(ASCII/Unicode)排列。如果你想要降序排序,就需要使用
reverse
登录后复制
参数。

reverse
登录后复制
参数是一个布尔值:

  • reverse=False
    登录后复制
    (默认值) 表示升序排序。
  • reverse=True
    登录后复制
    表示降序排序。
numbers = [10, 5, 8, 3, 12]
print(f"默认升序: {sorted(numbers)}") # 默认升序: [3, 5, 8, 10, 12]
print(f"降序: {sorted(numbers, reverse=True)}") # 降序: [12, 10, 8, 5, 3]
登录后复制

另一个非常重要且经常被忽视的特性是排序算法的稳定性。Python的排序算法是稳定的。这意味着什么呢?如果列表中有两个或多个元素,它们在排序时被判断为“相等”(即它们的

key
登录后复制
值相同),那么它们在排序后的相对顺序会保持不变。

这个特性在很多时候都至关重要,尤其是在进行多级排序时。举个例子,假设你有一份员工列表,你先按部门排序,然后你希望在每个部门内部,员工再按加入公司的时间排序。如果排序算法不稳定,那么你第二次按时间排序时,部门内部的员工顺序可能会被打乱,导致最终结果不符合预期。

Python使用一种名为 Timsort 的混合排序算法,它结合了归并排序和插入排序的优点。Timsort不仅效率高(平均和最坏情况都是O(n log n)),而且它就是一种稳定的排序算法。

我们来看一个稳定性示例:

data = [('apple', 3), ('banana', 1), ('cherry', 2), ('date', 1)]
# 假设我们想按元组的第二个元素排序,但希望当第二个元素相同时,保持原始顺序。
# 这里 'banana' 和 'date' 的第二个元素都是1。在原始列表中,'banana' 在 'date' 之前。

# 使用key按第二个元素排序
sorted_data = sorted(data, key=lambda item: item[1])
print(f"按第二个元素排序: {sorted_data}")
# 输出: [('banana', 1), ('date', 1), ('cherry', 2), ('apple', 3)]
# 注意:'banana' 依然在 'date' 之前,这证明了排序的稳定性。
登录后复制

很多时候,我们可能没意识到排序的“稳定性”有多重要,直到遇到需要多级排序的复杂场景,Timsort的这个特性就显得尤为贴心了。它省去了我们很多额外处理同值元素的麻烦,让数据处理逻辑更加清晰。

什么时候应该用
list.sort()
登录后复制
,什么时候用
sorted()
登录后复制
?排序性能有区别吗?

选择

list.sort()
登录后复制
还是
sorted()
登录后复制
,这其实是一个关乎数据处理哲学和具体场景需求的问题,不仅仅是性能考量。

什么时候用

list.sort()
登录后复制

  • 当你需要原地修改列表时: 这是最主要的理由。如果你不需要保留原始列表的状态,并且希望直接在现有列表上进行操作,
    sort()
    登录后复制
    是最直接且内存效率最高的方式。
  • 内存效率是关键时:
    sort()
    登录后复制
    不会创建新的列表对象,它直接在原列表的内存空间上进行操作。对于非常大的列表,这可以显著减少内存消耗。
  • 你不需要排序结果作为表达式的一部分时: 因为
    sort()
    登录后复制
    返回
    None
    登录后复制
    ,你不能直接将其结果赋值给另一个变量(除非你想要那个变量是
    None
    登录后复制
    )。它更像一个“命令”,告诉列表去排序自己。
my_large_list = list(range(1000000, 0, -1)) # 一个很大的倒序列表
# 如果只关心排序后的结果,不关心原始列表,且内存敏感
my_large_list.sort() # 原地修改,内存开销小
登录后复制

什么时候用

sorted()
登录后复制

  • 当你需要一个新的排序列表,同时保留原始列表时: 这是
    sorted()
    登录后复制
    最常见的用例。它提供了“不可变”操作的便利,让你可以安全地操作数据而不用担心副作用。
  • 当你需要排序的不是列表,而是其他可迭代对象时:
    sorted()
    登录后复制
    可以处理元组、集合、字典的键、值或项等任何可迭代对象,并始终返回一个列表。
  • 当你追求更函数式编程风格时:
    sorted()
    登录后复制
    更符合函数式编程中“无副作用”的理念,它接受输入,返回输出,不改变输入。
my_tuple = (5, 2, 8, 1)
sorted_list_from_tuple = sorted(my_tuple) # 返回新列表,元组不变
print(f"排序后的列表: {sorted_list_from_tuple}") # [1, 2, 5, 8]
print(f"原始元组: {my_tuple}") # (5, 2, 8, 1)

my_dict = {'b': 2, 'a': 1, 'c': 3}
sorted_keys = sorted(my_dict.keys()) # 排序字典的键
print(f"排序后的键: {sorted_keys}") # ['a', 'b', 'c']
登录后复制

排序性能有区别吗?

从时间复杂度的角度来看,

list.sort()
登录后复制
sorted()
登录后复制
都使用 Timsort 算法,因此它们的平均和最坏情况时间复杂度都是 O(n log n)。在绝大多数情况下,它们的执行速度差异非常小,几乎可以忽略不计。

然而,

sorted()
登录后复制
函数由于需要创建一个新的列表来存储排序结果,所以会有一个额外的内存分配和复制的开销。对于特别大的列表,这个开销可能会变得可感知。而
list.sort()
登录后复制
因为是原地操作,省去了这部分开销,理论上会略快一些。

但话说回来,我见过不少新手掉进

my_list = my_list.sort()
登录后复制
这个坑,然后纳闷为什么列表变成了
None
登录后复制
。这其实是Python设计哲学的一个体现:原地修改操作通常不返回自身,而是返回
None
登录后复制
,明确告诉你这个操作是副作用。如果你需要链式调用或者将排序结果赋值给变量,就必须使用
sorted()
登录后复制

所以,选择哪个,更多是根据你的业务逻辑和对数据是否需要保持原样的需求来决定。性能差异通常不是首要考虑因素,除非你正在处理的数据量大到足以让这些微小的差异变得重要。正确理解它们的行为和适用场景,远比纠结那一点点性能差异更有价值。

以上就是python怎么对列表进行排序_python列表排序方法详解的详细内容,更多请关注php中文网其它相关文章!

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号