登录
首页 >  文章 >  python教程

Python排序技巧:sorted与lambda使用全解析

时间:2025-07-14 19:46:28 417浏览 收藏

今日不肯埋头,明日何以抬头!每日一句努力自己的话哈哈~哈喽,今天我将给大家带来一篇《Python排序技巧:sorted与lambda应用详解》,主要内容是讲解等等,感兴趣的朋友可以收藏或者有更好的建议在评论提出,我都会认真看的!大家一起进步,一起学习!

Python中实现排序最常用的是sorted()函数和list.sort()方法。1.sorted()不改变原始数据,返回新列表;2.list.sort()是原地排序,直接修改原列表;3.两者都支持key参数,常使用lambda表达式定义排序规则。例如:可使用lambda按元组的某个元素、字符串长度、字典键值等排序;4.多条件排序可通过返回元组实现,如先按部门升序再按薪水降序;5.对于嵌套结构,可结合lambda提取深层数据进行排序。二者选择上,若需保留原始数据或处理非列表数据用sorted(),内存敏感或需原地修改用list.sort()。

怎样用Python实现排序?sorted与lambda

Python中实现排序,最常用的莫过于内置的sorted()函数和列表自带的sort()方法。它们都支持通过lambda表达式来定义自定义的排序规则,让数据按照你真正想要的逻辑排列。

怎样用Python实现排序?sorted与lambda

解决方案

在Python里,排序这件事儿,其实挺直观的。你手头要是有个序列,想把它排个序,最直接的办法就是用sorted()函数。它不改变原始序列,而是返回一个新的、已排序的列表。这就像你把一堆散乱的文件复印一份,然后整理复印件,原件还是乱的。

# 基础排序:数字和字符串
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_numbers = sorted(numbers)
print(f"默认数字排序: {sorted_numbers}") # 输出: [1, 1, 2, 3, 4, 5, 6, 9]

words = ["banana", "apple", "cherry", "date"]
sorted_words = sorted(words)
print(f"默认字符串排序: {sorted_words}") # 输出: ['apple', 'banana', 'cherry', 'date']

# 反向排序
reversed_numbers = sorted(numbers, reverse=True)
print(f"反向数字排序: {reversed_numbers}") # 输出: [9, 6, 5, 4, 3, 2, 1, 1]

那如果你的数据结构复杂一点,比如是个元组列表,你想按元组里的某个特定元素排序怎么办?这时候lambda函数就登场了,它就像一个“临时工”函数,随用随写,特别方便。lambda表达式通常用作sorted()list.sort()key参数。key参数接受一个函数,这个函数会在排序前对每个元素进行处理,然后用处理后的结果进行比较。

怎样用Python实现排序?sorted与lambda
# 使用lambda按元组的第二个元素排序
students = [('Alice', 25, 'A'), ('Bob', 20, 'B'), ('Charlie', 30, 'C')]
sorted_by_age = sorted(students, key=lambda student: student[1])
print(f"按年龄排序: {sorted_by_age}") # 输出: [('Bob', 20, 'B'), ('Alice', 25, 'A'), ('Charlie', 30, 'C')]

# 按字符串长度排序
fruits = ["apple", "banana", "kiwi", "grapefruit"]
sorted_by_length = sorted(fruits, key=lambda fruit: len(fruit))
print(f"按长度排序: {sorted_by_length}") # 输出: ['kiwi', 'apple', 'banana', 'grapefruit']

# 忽略大小写排序
names = ["Alice", "bob", "Charlie", "david"]
sorted_case_insensitive = sorted(names, key=lambda name: name.lower())
print(f"忽略大小写排序: {sorted_case_insensitive}") # 输出: ['Alice', 'bob', 'Charlie', 'david']

至于列表自己的sort()方法,它和sorted()最大的区别在于它是“原地”排序,直接修改原列表,不返回新列表。这在处理非常大的列表时,能省点内存。

my_list = [5, 2, 8, 1, 9]
my_list.sort() # 原地排序
print(f"列表原地排序: {my_list}") # 输出: [1, 2, 5, 8, 9]

# list.sort() 也支持 key 和 reverse 参数
my_students = [('Alice', 25), ('Bob', 20)]
my_students.sort(key=lambda s: s[1], reverse=True)
print(f"列表原地按年龄倒序: {my_students}") # 输出: [('Alice', 25), ('Bob', 20)]

Python排序中的key参数究竟有何魔力?

key参数,在我看来,是Python排序机制里最优雅也最强大的一个设计。它不是直接拿元素本身去比较,而是先用你提供的key函数处理一下每个元素,然后用处理后的“结果”去比较。这就像你在整理一堆书,你可能不想按书名首字母排,而是想按作者名字排,或者按出版年份排。key函数就负责从每本书里“提取”出那个作者名或出版年份。

怎样用Python实现排序?sorted与lambda

举个例子,假设你有一堆字典,代表着商品信息:

products = [
    {'name': 'Laptop', 'price': 1200, 'stock': 10},
    {'name': 'Mouse', 'price': 25, 'stock': 50},
    {'name': 'Keyboard', 'price': 75, 'stock': 20},
    {'name': 'Monitor', 'price': 300, 'stock': 5}
]

# 按商品价格排序
sorted_by_price = sorted(products, key=lambda p: p['price'])
print("按价格排序:")
for p in sorted_by_price:
    print(p)
# 输出会是:Mouse, Keyboard, Monitor, Laptop

# 按库存量从高到低排序
sorted_by_stock_desc = sorted(products, key=lambda p: p['stock'], reverse=True)
print("\n按库存量倒序:")
for p in sorted_by_stock_desc:
    print(p)
# 输出会是:Mouse, Keyboard, Laptop, Monitor

这里lambda p: p['price']就告诉sorted(),对于每个字典p,我关心的是它的'price'键对应的值。sorted()就拿这些价格去比较。这种“映射-比较”的模式,让排序变得异常灵活。你甚至可以对一个自定义类的对象进行排序,只要key函数能提取出你想要的比较依据。

class Item:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __repr__(self): # 方便打印
        return f"Item('{self.name}', {self.weight}kg)"

items = [Item('Stone', 50), Item('Feather', 0.1), Item('Book', 2)]

# 按重量排序
sorted_items = sorted(items, key=lambda item: item.weight)
print(f"\n按重量排序: {sorted_items}")
# 输出: [Item('Feather', 0.1kg), Item('Book', 2kg), Item('Stone', 50kg)]

key参数的强大之处在于它将“如何比较”的逻辑与“比较什么”的逻辑分离了。你无需写复杂的比较函数,只需告诉Python“我要用这个值来代表我的元素进行比较”,剩下的它就帮你搞定了。

sorted()list.sort():何时选择,如何权衡?

这俩兄弟,虽然都能排序,但用起来还是有些讲究的。我个人在日常编码中,大部分时候会优先考虑sorted(),因为它不会改变原始数据。这种“非侵入性”或者说“纯函数”的特性,在很多场景下能避免一些意想不到的副作用,尤其是在函数式编程风格或需要保持原始数据完整性的时候。

  • sorted():

    • 返回新列表: 它总是创建一个新的已排序的列表,原始的可迭代对象保持不变。
    • 通用性强: 不仅仅是列表,任何可迭代对象(如元组、字符串、集合、字典的键等)都可以用sorted()进行排序。
    • 内存开销: 因为要创建新列表,所以对于非常大的数据集,可能会有额外的内存开销。
    • 示例: new_list = sorted(my_tuple)
  • list.sort():

    • 原地排序: 它直接修改列表本身,不返回任何值(返回None)。
    • 仅限列表: 只能用于列表对象。
    • 内存效率: 由于是原地操作,它通常在内存使用上更高效,对于内存敏感或超大型列表是首选。
    • 示例: my_list.sort()

什么时候用哪个?这其实是个权衡。

如果你需要保留原始列表,或者你的数据不是列表(比如你只想对一个元组排序然后得到一个新的列表),那么sorted()是你的不二之选。它给你一个干净的新结果,不影响旧数据。

而如果你确定只需要排序列表本身,并且不介意它被修改,或者你正在处理一个内存非常大的列表,list.sort()就显得更高效了。比如,你从数据库里捞出来一个巨大的列表,只想把它按某个字段排个序,然后接着处理,那么直接list.sort()会比先复制再排序来得快。

一个常见的“坑”是,新手可能会写my_list = my_list.sort(),然后发现my_list变成了None。记住,list.sort()不返回列表,它修改的是原列表。

data_tuple = (5, 1, 9, 3)
# data_tuple.sort() # 这会报错,因为元组没有sort方法
sorted_data = sorted(data_tuple)
print(f"元组排序结果 (sorted): {sorted_data}") # 输出: [1, 3, 5, 9]
print(f"原始元组: {data_tuple}") # 输出: (5, 1, 9, 3) - 保持不变

large_list = list(range(1000000, 0, -1)) # 假设这是一个非常大的列表
# sorted_large_list = sorted(large_list) # 这会创建一份拷贝,可能消耗更多内存
large_list.sort() # 更高效地原地排序
print(f"大型列表是否已排序 (部分检查): {large_list[:5]}...") # 输出: [1, 2, 3, 4, 5]...

在稳定性方面,Python的排序算法是稳定的。这意味着如果两个元素在排序key值上相等,它们在排序后的相对顺序会保持不变。这在多条件排序时非常有用,比如你先按年龄排序,再按姓名排序,如果年龄相同,姓名就会保持原有的相对顺序。

多条件排序与复杂数据结构:lambda函数的进阶应用

当你的排序需求变得复杂,比如需要按多个条件进行排序,或者处理的数据结构嵌套更深时,lambda函数配合key参数的威力就体现出来了。这就像你不仅仅想按作者排序,还想在作者相同的情况下,再按出版年份排序。

Python的key函数可以返回一个元组。当key函数返回元组时,sorted()会按元组的第一个元素进行比较,如果第一个元素相同,就比较第二个元素,以此类推。这简直是为多条件排序量身定制的。

假设你有一个员工列表,你想先按部门排序,如果部门相同,再按薪水从高到低排序:

employees = [
    {'name': 'Alice', 'dept': 'HR', 'salary': 60000},
    {'name': 'Bob', 'dept': 'IT', 'salary': 80000},
    {'name': 'Charlie', 'dept': 'HR', 'salary': 75000},
    {'name': 'David', 'dept': 'IT', 'salary': 70000},
    {'name': 'Eve', 'dept': 'HR', 'salary': 60000}
]

# 先按部门升序,再按薪水降序
sorted_employees = sorted(employees, key=lambda emp: (emp['dept'], -emp['salary']))
# 注意:对数字使用负号可以实现降序排列,因为默认是升序。
# 或者使用itemgetter,但lambda更直接。

print("按部门升序,薪水降序排序的员工:")
for emp in sorted_employees:
    print(emp)
# 输出会是:
# HR部门的Alice (60000), Eve (60000) - 薪水相同,保持原始相对顺序
# HR部门的Charlie (75000)
# IT部门的Bob (80000)
# IT部门的David (70000)

在这个例子中,lambda emp: (emp['dept'], -emp['salary'])返回了一个元组。sorted()会先比较'dept',如果'dept'相同,再比较-emp['salary']。因为我们希望薪水是降序,所以取了负值,这样数值越大,负值越小,在升序比较时反而排在前面。

处理更复杂的嵌套结构也是类似的。只要你的lambda函数能“挖”出你想要的比较依据,无论数据藏得多深,排序都能搞定。

# 假设有课程和学生信息,按课程ID排序,然后按学生姓名排序
courses_data = [
    {'course_id': 'CS101', 'students': [{'name': 'Zoe'}, {'name': 'Amy'}]},
    {'course_id': 'MA202', 'students': [{'name': 'Bob'}, {'name': 'Carl'}]},
    {'course_id': 'CS101', 'students': [{'name': 'David'}, {'name': 'Eve'}]}
]

# 假设我们想按课程ID排序,然后对每个课程内部的学生按姓名排序
# 这需要两步操作,或者更复杂的结构,但如果只是排序最外层列表,可以这样:
sorted_courses_by_id = sorted(courses_data, key=lambda c: c['course_id'])
print("\n按课程ID排序:")
for c in sorted_courses_by_id:
    print(c)
# 输出: CS101, CS101, MA202 (课程ID相同,顺序可能不变)

# 如果想对每个课程内的学生列表也排序,那需要单独处理
for course in courses_data:
    course['students'].sort(key=lambda s: s['name'])

print("\n课程内学生按姓名排序后的课程数据:")
for c in courses_data:
    print(c)
# 输出: CS101 (Amy, Zoe), MA202 (Bob, Carl), CS101 (David, Eve)

这里展示了,对于嵌套结构,你可能需要组合使用sorted()list.sort(),或者进行多步操作。lambda函数在提取深层数据作为key方面,提供了极大的便利。它避免了你需要为每个特定的排序需求都写一个完整的def函数,使得代码更加简洁和即时。

今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>