Python 列表有一个内置的 list.sort() 方法可以直接修改列表、进行排序。还有一个 sorted() 内置函数,它会从一个可迭代对象构建一个新的排序列表。在本文中,我们将探索使用 Python 对数据进行排序的各种技术。
首先,我们需要明确的是,本文讲解的是 Python 列表的排序方法。而 Python 中的字典是无序的,所以字典本身不存在排序问题。但有时候我们需要对字典中的键值对排序,那么先转为列表或可迭代对象,然后再调用列表的排序方法就行了。
简单的升序排序非常容易:只需调用 sorted() 函数即可,它返回一个新的已排序列表。
>>> a = [5, 2, 3, 1, 4]
>>> a
[5, 2, 3, 1, 4]
>>> b = sorted(a)
>>> b
[1, 2, 3, 4, 5]
你也可以用 list.sort() 方法。它会直接修改原列表(并返回 None
以避免混淆),通常来说它不如 sorted() 方便——但如何你不需要原李彪,它会更有效率。
>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]
另一个区别是 list.sort() 方法仅为列表定义,而 sorted() 函数接受任何可迭代对象输入(一般来说,可用 for
循环进行迭代的对象都是可迭代对象,如列表、字典、集合、字符串等等)。
>>> a = {5, 2, 3, 1, 4} # 定义一个集合类型的变量
>>> b = sorted(a)
>>> b
[1, 2, 3, 4, 5]
>>> a.soted() # .sort()是列表的排序方法,不支持其它数据类型, 所以会报错
Traceback (most recent call last):
File "" , line 1, in <module>
AttributeError: 'set' object has no attribute 'soted'
list.sort() 和 sorted() 都有一个 key
形参用来指定在进行比较前要在每个列表元素上调用的函数(或其它可调用对象)。
key
形参的值应该是个函数(或其他可调用对象),它接受一个参数并返回一个用于排序的键。这种机制速度很快,因为对于每个输入记录只会调用一次键函数。
一种常见的模式是用一些对象的索引作为键对复杂对象进行排序。例如:
>>> stds = [ # 姓名,成绩,年龄
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(stds, key=lambda std: std[2]) # 根据年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
list.sort() 和 sorted() 都接受布尔值的 reverse
参数。这用于标记降序排序。例如,要以反向 age
顺序获取学生数据。
>>> stds = [ # 姓名,成绩,年龄
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(stds, key=lambda std: std[2], reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
字典的 .items()
方法是可迭代对象,可以利用 sorted()
函数进行排序。
>>> dt = {'a': 1, 'c': 3, 'b': 5}
>>> sorted(dt.items(), key=lambda x: x[0]) # 按键排序,返回列表
[('a', 1), ('b', 5), ('c', 3)]
>>> sorted(dt.items(), key=lambda x: x[1]) # 按值排序,返回列表
[('a', 1), ('c', 3), ('b', 5)]
上面展示的键函数模式非常常见,因此 Python 提供了更方便的函数,使访问器函数更容易、更快捷。operator 模块有 itemgetter() 、 attrgetter() 和 methodcaller() 函数。
使用这些函数,上述示例会变得更简单、更快捷:
>>> from operator import itemgetter, attrgetter
>>> stds = [
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(stds, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
operator 模块函数允许多级的排序。例如,先按成绩排序,再按年龄排序。
>>> from operator import itemgetter, attrgetter
>>> stds = [ # 姓名,成绩,年龄
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(stds, key=itemgetter(1, 2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
排序保证是稳定的。这意味着当多条记录有相同的键时,将保留其原始顺序。
>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=lambda x: x[0])
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]
https://docs.python.org/3/howto/sorting.html