python 排名函数_深入理解 Python 中的排序函数

由于 Python2 和 Python3 中的排序函数略有区别,本文以Python3为主。

Python 中的排序函数有 sort ,sorted 等,这些适用于哪些排序,具体怎么用,今天就来说一说。

两个函数的区别

这儿直接给出这两个排序函数的区别sort 可以直接改变所排序的变量,而 sorted 不会

sort 是 list 的内建函数,不能用于字典的排序,而 sorted 可以用于列表、元组、字典的排序

函数原型

sort

sort 函数原型如下,其中 L 是列表元素

L.sort(*, key=None, reverse=False)

参数解释:key

key 也是接受一个函数,不同的是,这个函数只接受一个元素,形式如下

def f(a):

return len(a)

key 接受的函数返回值,表示此元素的权值,sort 将按照权值大小进行排序,通常的我们会以 lambda 的形式展现出来,比如

key = lambda x : len(x)reverse

接受False 或者True 表示是否逆序

sorted

sorted 函数原型如下,返回的是一个列表

sorted(iterable, *, key=None, reverse=False)

参数解释:iterable

可以迭代的对象,可以是 list,tuple,dict.items(),dict.keys()或者自定义的类key

和 sort 中的含义相同reverse

和 sort 中的含义相同

实战演练

下面针对不同 Python 类型进行排序。

基础篇

list

# sort 内置函数

a = [14,4,2,19,37,23]

a.sort() #改变原有列表

print(a) #[2, 4, 14, 19, 23, 37]

# sorted 函数

b = [14,4,2,19,37,23]

c = sorted(b) #不改变原有列表

print(b) #[14, 4, 2, 19, 37, 23]

print(c) #[2, 4, 14, 19, 23, 37]在这里,可以看出 sort 是没有返回值的,它会改变原有的列表,而 sorted 需要用一个变量进行接收,它并不会修改原有的列表

tuple

# sorted 函数

b = (14,4,2,19,37,23)

c = sorted(b) #不改变原有列表

print(b) #(14, 4, 2, 19, 37, 23)

print(c) #[2, 4, 14, 19, 23, 37]这里⚠️注意了:对于元组来说,是没有内置函数 sort 的,只能使用 sorted 函数,而且 sorted 函数返回的是 list 类型哦,不能弄错了~~~

dict

这个类型相对复杂一点,多数情况下需要用到 key 参数,但是也不是很复杂,后面的进阶篇会详细讲解

# sorted 函数

a = {"today":2020,"pre":2019,"next":2021}

b = sorted(a.items()) #不改变原有列表

c = sorted(a.items(), key = lambda x:(x[1],x[0]))

print(b) #[('next', 2021), ('pre', 2019), ('today', 2020)]

print(c) #[('pre', 2019), ('today', 2020), ('next', 2021)]如果不加 key 参数,就是默认按照键进行排序,加上 key 参数之后可以按照自己定义的规则来进行排序。

进阶篇

上面的基础篇讲的是最基本的排序方法,但是在实际应用中碰到的情况都比这个复杂怎么办?easy,进阶篇他来了。

自定义规则排序

自定义的排序主要通过参数 key 实现,我们来看看

from operator import itemgetter, attrgetter

student_tuples = [

('john', 'A', 15),

('jane', 'B', 12),

('dave', 'B', 10),

]

a = sorted(student_tuples, key = lambda x : x[2]) # 使用 lambda

b = sorted(student_tuples, key = itemgetter(2)) # 使用 itemgetter

c = sorted(student_tuples, key = lambda x : (x[1],x[2])) # 使用 lambda 进行多重排序

d = sorted(student_tuples, key = itemgetter(1,2)) # 使用 itemgetter 进行多重排序

print(a)

print(b)

print(c)

print(d)

结果如下

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

可以看到,key 关键字可以通过 lambda 和 itemgetter 方式实现,既可以实现单一字段的排序,还可以进行多重字段的排序,是不是很省时省力?

自定义类排序

前面讲的都是 Python 的内置类型,那么碰到我们自定义的类型该怎么去排序,其实道理是一样的,假设我们定义的类如下

class Student:

def __init__(self, name, grade, age):

self.name = name

self.grade = grade

self.age = age

def __repr__(self):

return repr((self.name, self.grade, self.age))

咱们先来个简单的栗子

student_objects = [

Student('john', 'A', 15),

Student('jane', 'B', 12),

Student('dave', 'B', 10),

]

sorted(student_objects, key=lambda student: student.age) # sort by age

#[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

我们再利用 operator 模块进行排序

from operator import itemgetter, attrgetter

a = sorted(student_objects, key=attrgetter('age'))

b = sorted(student_objects, key=attrgetter('grade', 'age'))

print(a)

print(b)

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]这个过程和前面的内置类型比较几乎一样,差别就在于使用函数分别是 itemgetter, attrgetter,简单的说 itemgetter 是以 index 的形势来获取相对应的值,而 attrgetter 是用 key 来获取相对应的值。具体的区别可以看看 这篇博客。

这里有人就会问了?如果我想先以年龄升序,再以年级降序进行排序那该怎么写?这个就比较复杂了,有两种方法,听我娓娓道来。多重排序函数定义

这种方法定义起来需要有点技巧性,拿上面的学生数据举例吧

def multisort(xs, specs):

for key, reverse in specs:

xs.sort(key=attrgetter(key), reverse=reverse)

return xs

multisort(list(student_objects), (('grade', True), ('age', False)))

#[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

看的出来这种定义的技巧相对比较重要,对于非列表的比较和列表的比较大同小异,这里不赘述。使用老方法 cmp 比较函数

这个 cmp 参数到了 Python3 就给取消了不过还是可以通过其他方式给实现,过程繁琐,首先得定义一个比较函数

def cmp_to_key(mycmp):

'Convert a cmp= function into a key= function'

class K:

def __init__(self, obj, *args):

self.obj = obj

def __lt__(self, other):

return mycmp(self.obj, other.obj) < 0

def __gt__(self, other):

return mycmp(self.obj, other.obj) > 0

def __eq__(self, other):

return mycmp(self.obj, other.obj) == 0

def __le__(self, other):

return mycmp(self.obj, other.obj) <= 0

def __ge__(self, other):

return mycmp(self.obj, other.obj) >= 0

def __ne__(self, other):

return mycmp(self.obj, other.obj) != 0

return K

这里的 mycmp 函数是自己定义的,我这定义的如下

def cmp(a, b):

if a.age > b.age:

return 1

elif a.age < b.age:

return -1

else:

return a.grade - b.grade

sorted(student_objects, key=cmp_to_key(cmp))

# [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

这俩结果是一样的,只不过后一种方法代码较长,但是思路简单,前面一种代码短,但是思路复杂一些,推荐前面一种方法,既可以锻炼思维,还能减少代码量。

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值