python中的排序方法都有哪些_聊聊Python的排序方法

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS

一、最基本的排序

取一个可迭代类型的实例,就可以用Python的内建sorted函数对其排序。默认情况下是由小到大排序,返回值是一个list。比如最常见的对list进行排序:

print(sorted([3,2,4])) # [2,3,4]

既然是可迭代类型,给一个字符串也可以:

print(sorted('hello')) #['e', 'h', 'l', 'l', 'o']

使用sorted的reverse参数可以指定从大到小:

print(sorted([3,2,4],reverse=True)) # [4,3,2]

注意不要把sorted函数和list类的sort成员函数搞混。list.sort是进行原地操作,比较适合节省空间的场合。在本文我们不讨论list.sort。

二、什么东西组成的序列可以排序

简单的说,对于一个可迭代类型的实例,如果它的元素是能够相互比较(也就是可以用 = 和 < 或 > 操作符操作的)的,那么这个序列就可以被排序。

我们又知道,Python中万物皆对象,Python的操作符无非就是调用对象的成员函数(见https://zhuanlan.zhihu.com/p/20584316)。因此我们也可以自己设计一个能比较的类型。下面就是一个例子,对扑克牌的单张面值进行比较(不考虑王)

class Card:

def __init__(self,x):

self.x = x

x = x.upper()

MAP = {

'10' : 10,

'J' : 11,

'Q' : 12,

'K' : 13,

'A' : 14,

'2' : 15

}

if x >= '3' and x <= '9':

self.v = int(x)

elif x in MAP.keys():

self.v = MAP[x]

else:

self.v = None

def __eq__(self,other):

return self.v == other.v

def __lt__(self,other):

return self.v < other.v

def __repr__(self):

return self.x

我们看到Card类里,在构造函数中把扑克牌的面值映射为一个数字,比如把J映射为11等。当然你也可以根据不同的玩法进行不同的映射,例如把J、Q、K都映射为10等等。

接下来我们注意到这个类实现了__eq__和__lt__,这样的话,Card类的实例就能接受=和<这两个操作符的操作了。但不必实现<=和>,这是因为sorted内部会进行推断。当然你也可以实现=和>(即函数__gt__),只要逻辑上完备,能够推理出 =、<、<=、>=、>这所有的比较操作就可以。

我们先看看效果

print(Card('5') < Card('2')) #True

下面就可以比较了。注意由于Card类实现了__repr__,所以可以直接被print出来

print(sorted([Card('5'),Card('3'),Card('2'),Card('Q')])) # [3, 5, Q, 2]

三、映射排序

映射排序的含义是,给定一个序列A,用一个映射函数将其N对1的映射到另一个序列集合B,对B进行排序,然后返回B的原象。

比如说有一个字符串序列['a','bbb','cc'],我们想对按字符串的长度排序,即短的字符串排在前面。这样的话我们就要找一个映射函数,即内建的len,先把['a','bbb','cc']映射为[1,3,2],然后对新的序列进行排序,得到[1,2,3],之后再反推得到['a','cc','bbb']

那么用户只需要写好映射函数,使用sorted的key函数指定之。其后sorted函数会帮助我们完成反推。例子如下:

print(sorted(['a','bbb','cc'],key=len)) #['a', 'cc', 'bbb']

映射排序是稳定且保序的。也就是说如果A中的两个元素被映射成了B中的同一个元素,那么在最终的结果里,这两个元素的排序与A中的排序相同。例如

print(sorted(['a','ee','bbb','cc','ddd'],key=len)) #['a', 'ee', 'cc', 'bbb', 'ddd']

我们看到'ee'与'cc'的长度相同,在结果里它们的顺序也是'ee'在前面。

注意参数key一定是一个callable的东西。比如下面这个例子,我们针对元组的第二个元素进行排序:

print(sorted([('A',3),('B',3),('C',2),('D',4)],key=lambda x:x[1])) #[('C', 2), ('A', 3), ('B', 3), ('D', 4)]

四、自定义比较函数

旧版的sorted还有一个参数cmp,可以传入一个函数,自由的决定两个元素的大小。然而这个函数在Python3当中已经被删除。

对于能够用key替代的cmp的需求,推荐的方法是直接用key而不是cmp,据说对性能有较大的提升。如果认为某些需求难以用key实现,则仍然可以写一个返回-1,0,1的比较函数,而后用functools.cmp_to_key这个函数将cmp函数转换为key。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值