Python系列之sorted函数使用

这篇文章对sorted函数进行了详细的学习和理解,主要包括其排序的原理和过程以及 key函数的理解,最后结合了对两个常用情形示例的解读加深了理解

sorted函数简介

sorted() 函数可以对所有序列(可迭代的对象)进行排序操作,并且不会修改原始的序列,而是生成一个新的列表list

Sorted() sorts any sequence (list, tuple, dict) and always returns a list with the elements in sorted manner, without modifying the original sequence.

和列表的sort函数的区别:

  • sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
  • listsort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。

sorted函数语法

1
sorted(iterable, *, key=None, reverse=False)
  • iterable:可迭代对象
  • key:键函数,这个参数很关键,它接受一个参数并返回另一个用作排序键的值;更通俗地来说,键函数的作用就是在排序开始之前对iterable中的每个元素进行转换(转换的结果可以是一个字符、数字或者列表),然后使用转换之后的元素而不是原始的元素进行排序,从而得到一个排序的索引,最终将该索引再map回原始元素来得到最终的排序结果
  • reverse:排序规则,reverse = True表示按照ASCII码降序排列 , reverse = False 表示按照ASCII码升序(默认)排列

基础使用

key函数的理解

对字典进行排序:

1
2
3
4
5
6
7
8
9
10
11
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
x.items()
dict_items([(1, 2), (3, 4), (4, 3), (2, 1), (0, 0)])

# 按照字典的value值进行排序,所以使用的是item[1]
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

# 按照字典的key进行排序
{k: v for k, v in sorted(x.items(), key=lambda item: item[0])}
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

在按照value值排序是,key函数的作用就相当于将最开始的对[(1, 2), (3, 4), (4, 3), (2, 1), (0, 0)]排序转换为了对[2,4,3,1,0]的排序,在对[2,4,3,1,0]排完序后会得到一个索引,最后将该索引应用于[(1, 2), (3, 4), (4, 3), (2, 1), (0, 0)]即可完成排序。


对iterable的理解

简单的可迭代对象

1
2
3
4
5
6
7
# 对列表排序
sorted([1,2,4,3])
[1, 2, 3, 4]

# 对字符串排序
sorted('adcb')
sorted('adcb')

简单的可迭代对象的比较非常容易理解,就是单个元素之间的比较。

嵌套的可迭代对象

1
2
3
a=['aef','abc']
sorted(b)
['abc', 'aef']

上面是列表可迭代对象嵌套字符串可迭代对象的排序,排序时对内部的两个字符串可迭代对象按照位置依次比较'a'->'a''b'->'e''c'->'f',只要出现一个可以区分出顺序如'b' > 'e',那么比较就结束,最终顺序就是['abc', 'aef']

需要注意的是,不能将数字和字符串直接进行比较

1
2
3
4
5
sorted(['test',1])
TypeError: '<' not supported between instances of 'int' and 'str'

sorted(['test','1'])
['1', 'test']

再多一层嵌套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a=['test',1]
b=['abc','def']

# 这个其实是'abc'和'test',因为已经区分出顺序了
# 所以不能进行后续的'def'和1的比较,不然就会报错
sorted([a,b])
[['abc', 'def'], ['test', 1]]


# 如果是下面这种情况
a=['abc',1]
b=['abc','def']

# 因为'abc'和'abc'不能区分出顺序,所以会进行'def'和1的比较
sorted([a,b])
TypeError: '<' not supported between instances of 'int' and 'str'


进阶使用

对字母和数字混用的字符串排序

这种排序也叫natural sort,在Linux写试用sort命令加上-V参数即可实现,但是在Python中并没有这种方法,所以需要自己想办法,下面是Python analog of PHP’s natsort function (sort a list using a “natural order” algorithm)中一个回答的代码,这里学习一下:

1
2
3
4
import re
def natural_key(string_):
"""See http://www.codinghorror.com/blog/archives/001018.html"""
return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)]

使用:

1
2
3
test=['image1.jpg', 'image12.jpg', 'image15.jpg', 'image3.jpg']
sorted(test, key=natural_key)
['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']

代码解读:
首先是使用了列表内涵,并且嵌套了forif这两个流程控制,还原代码:

1
2
3
4
5
for s in re.split(r'(\d+)', string_):
if s.isdigit():
int(s)
else:
s

需要注意的就是这种带条件判断的列表内涵中if的位置,之前使用的列表内涵一般都是将代码结构线性铺开,而这里是将if条件判断前移,主要原因是else语句的存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a=[1,2,3,4,5]
# 如果不存在else语句,最后的输出值就只有i
[i for i in a if i<3]
[1, 2]

# 多了else语句就相当于多了输出值
a=[1,2,3,4,5]
# 再次线性铺开就会报错
[i for i in a if i<3 else 0]
SyntaxError: invalid syntax

# if语句前移即可
[i if i<3 else 0 for i in a ]
[1, 2, 0, 0, 0]

代码解读完了再回归到这里的sorted函数上来,之前也说过,key函数的作用其实就是在排序开始之前将原始的元素进行转换,然后使用转换之后的元素进行排序,这里的natural_key函数也是一样:

1
2
3
4
# natural_key函数对原始元素的转换
# 转换完之后再结合之前的内容将就不难理解排序的过程了
[int(s) if s.isdigit() else s for s in re.split(r'(\d+)', 'image1.jpg') ]
['image', 1, '.jpg']


依据另一个列表的顺序排序

需求:

1
2
3
4
5
a = ['c','d','b','a','e']
b = ['a001','b002','c003','d004','e005']

# 依据a列表中元素的顺序来对b列表进行排序
c = ['c003','d004','b002','a001','e005']

解决方法:

1
2
3
4
c = sorted(b, key = lambda x: a.index(x[0]))

a.index('c')
0

解读:这里与前面对原始的列表元素进行转换并使用转换后的元素进行排序并最终得到索引的方法不同,这里得到索引的方式也是对原始元素进行转换然而不是对转换后的元素进行排序,而是查询转换后的元素在另一个列表中的顺序来得到索引


参考链接



-----本文结束感谢您的阅读-----

本文标题:Python系列之sorted函数使用

文章作者:showteeth

发布时间:2020年06月13日 - 22:37

最后更新:2020年06月14日 - 10:43

原始链接:http://showteeth.tech/posts/217.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%