跳到正文
效率工具实用笔记关于本站
表格与数据

sorted和list.sort怎么选:排序时保留原始列表

约 6 分钟阅读AI 辅助整理

当你想排序又不想改动原列表时,用sorted并配合key和reverse;它会返回一个新列表,原列表保持原样。本文用自建记录演示按字段排序和降序排列,并说明如何核对原列表未被改动。

本文要点

  1. 假设你在练习目录里准备了几条自建记录,每条记录是一个小字典,包含名称和数量两个字段

  2. sorted默认按元素本身比较

sorted和list.sort怎么选:排序时保留原始列表的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

要保留原列表,就用sorted而不是原地排序

如果你手里有一份记录列表,想按某个字段排好序,同时又不能把原来的顺序弄丢,那么选择标准只有一条:用sorted,不用list.sort。

按Python官方文档的说明,sorted(iterable, *, key=None, reverse=False)从iterable中的项返回一个新的排序列表。也就是说,它不修改传入的可迭代对象,而是把排好序的结果作为新列表交给你。原列表仍然指向原来的对象,顺序不变。

这就是“保留原始列表”的实现方式:原列表留着,新列表单独接住。

本文只讨论sorted的key和reverse两个参数,用自建的记录列表做示例。不涉及list.sort的原地细节,也不涉及其他排序参数。所有数据都是练习用的自建示例,不是真实业务数据。动手前建议在练习目录里新建脚本,例如exercise/sort_demo.py,不要拿重要数据直接试。

自建记录:先写清楚输入长什么样

假设你在练习目录里准备了几条自建记录,每条记录是一个小字典,包含名称和数量两个字段。下面这段只是把数据写进脚本,不读取任何外部文件:

records = [
    {"name": "绿茶", "qty": 3},
    {"name": "红茶", "qty": 1},
    {"name": "乌龙", "qty": 2},
]

这份列表的原始顺序是绿茶、红茶、乌龙。后面无论怎么排序,我们都要能回头确认这个顺序还在。

为了核对,可以在排序前先把原始顺序复制一份留底:

original = [r["name"] for r in records]
print(original)

运行后会打印出原始名称顺序。这一步是编辑建议的核对方法,不是必须步骤,但它能让你在排序后直接对比,确认原列表没被动过。

用key指定按哪个字段排

sorted默认按元素本身比较。对字典来说,直接比较字典没有意义,所以要用key告诉它:拿每个元素的哪一部分去比。

key接收一个函数,sorted会对每个元素调用它,用返回值作为排序依据。按数量字段排序可以写成:

by_qty = sorted(records, key=lambda r: r["qty"])
print(by_qty)

这里lambda r: r["qty"]的作用是:对每条记录取出qty的值,sorted按这些数值从小到大排列。结果是数量1、2、3对应的记录依次排开。

关键点在于:by_qty是一个新列表,records还是原来那三条、原来那个顺序。你可以打印records再确认一次。

如果不想用lambda,也可以先定义一个普通函数,把函数名传给key,效果一样。选哪种只是写法差异,不影响返回新列表这一点。

用reverse改成从大到小

默认是从小到大。想反过来,把reverse设为True:

by_qty_desc = sorted(records, key=lambda r: r["qty"], reverse=True)
print(by_qty_desc)

reverse=True表示降序排列,数量3的记录排在最前。reverse默认是False,也就是升序,所以不写它时就是从小到大。

这里要分清一件事:reverse改变的是排序方向,不是把升序结果倒过来再处理一遍。你只需要在调用时给出这个参数,sorted返回的新列表就是按降序排好的。

同样地,by_qty_desc是新列表,records不受影响。

排序后怎么核对原列表没被改动

光看代码容易漏掉“原列表到底动没动”这一步。可以用下面的方式核对(以下为编辑建议的检查方法,不是对某个程序的实测记录):

1. 排序前记录原始顺序,例如打印[ r["name"] for r in records ]。

2. 调用sorted,把结果赋给一个新变量。

3. 排序后再次打印records的名称顺序,和第一步对比。

4. 如果两次输出一致,说明原列表顺序未变;如果变了,检查是不是误用了原地排序方法。

这个核对的价值在于:sorted返回新列表是它的定义行为,但你在实际代码里可能把结果又赋回了原变量名,看起来像“原列表被改了”。例如写成records = sorted(records, ...),这时records这个名字指向了新列表,原来的列表对象虽然还在,但你已经拿不到它了。要保留原始列表,就别把新结果赋回同一个名字。

什么时候这种选择不适用

sorted返回新列表,代价是额外占用一份列表空间。如果你的列表非常大,又确实不需要保留原顺序,原地排序在内存上更省。但本文的范围是“排序时保留原始列表”,在这个前提下,sorted是直接对应的工具。

另外,key函数返回的值必须能相互比较。如果某条记录缺少qty字段,或者字段值类型不一致,排序时会报错。这不是sorted本身的问题,而是数据不齐导致的。遇到报错时,先检查每条记录是否都有key要取的那个字段。

本文只覆盖sorted的key和reverse,以及它返回新列表这一行为。list.sort的原地细节、稳定性、多级排序等内容不在本文范围内。所有示例均为自建练习数据,结论只针对这些示例的输入输出。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回表格与数据 →