今天的内容很简单,我们有一个序列,如何找到该序列中最大或者最小的N个元素?千万别走开,看到后面会有干货分享哦!
这种排序真的简单吗?
一个例子
先举个例子
l = [1,2,4,3,6,0,5,7,9]
该列表中的组大值
>>>print(max(l))
9
该列表中的最小值
>>>print(min(l))
问题来了,我们想知道该列表中最大的3个值或者最小的3个值该怎么办呢?
一般方法
# 先对序列进行排序
sorted(l)
# 然后打印输出
>>>print("前三个:{},后三个:{}".format(l[:3], l[-3:]))
前三个:[1, 2, 4],后三个:[5, 7, 9]
成功实现。
但仅仅这样就可以了吗?我们的干货还没出现呢?先给大家推荐一入门书,里面有很多案例,涉及一些pygame模块的实战项目,感兴趣的朋友们关注下,喜欢阅读正版Python书的朋友们可以入手哦。
接着上面的内容。我们继续……例子扩展
上面的简单列表我们通过排序可以实现,但是复杂一点的列表呢?
复杂一点的例子?
复杂列表如下:
scoreInfo=[
{'name':'Lucy','en_score': 89.6,'math_scroe':94.1},
{'name':'Bob','en_score': 72.4,'math_scroe':84.2},
{'name':'LiLei','en_score': 82.6,'math_scroe':74.1},
{'name':'HanMeimei','en_score': 65.6,'math_scroe':86.9},
{'name':'Lily','en_score': 78.1,'math_scroe':65.8},
{'name':'Tracy','en_score': 72.6,'math_scroe':65.4},
]
按照英语成绩'en_score'对学生进行排名,找出前3名和后3名。
解决方案
仍然使用上面的排序思路:先将列表按照每一项中的'en_score'进行排序,然后输出前后三个即可。对于字典排序,我们前面讲过(参见杂乱无章的数据结构如何进行排序,简明讲述Python字典排序那些事)
还是排序
实现如下:
t_scoreInfo = sorted([item for item in scoreInfo], key=lambda x: x['en_score'], reverse=True)
>>>print('前三个:{}\n后三个:{}'.format(t_scoreInfo[:3], t_scoreInfo[-3:]))
前三个:[{'name': 'Lucy', 'en_score': 89.6, 'math_scroe': 94.1}, {'name': 'LiLei', 'en_score': 82.6, 'math_scroe': 74.1}, {'name': 'Lily', 'en_score': 78.1, 'math_scroe': 65.8}]
后三个:[{'name': 'Tracy', 'en_score': 72.6, 'math_scroe': 65.4}, {'name': 'Bob', 'en_score': 72.4, 'math_scroe': 84.2}, {'name': 'HanMeimei', 'en_score': 65.6, 'math_scroe': 86.9}]
成功完成!
这样就完了?
上面的方法貌似都可以实现该需求,还有别的方案吗?我们知道,碰到类似的问题,应该向内置函数求解。没错,内置函数提供了这样的方法。
还没结束!
导入模块
import heapq
简单序列
l = [1,2,4,3,6,0,5,7,9]
>>>print('前三:{}'.format(heapq.nlargest(3, l)))
前三:[9, 7, 6]
>>>print('后三:{}'.format(heapq.nsmallest(3, l)))
后三:[0, 1, 2]
复杂序列
还是scoreInfo列表
high =heapq.nlargest(3,scoreInfo,key=lambdas:s['en_score'])
low = heapq.nsmallest(3, scoreInfo, key=lambda s: s['en_score'])
>>>print("前三:{}\n后三:{}".format(high, low))
前三:[{'name': 'Lucy', 'en_score': 89.6, 'math_scroe': 94.1}, {'name': 'LiLei', 'en_score': 82.6, 'math_scroe': 74.1}, {'name': 'Lily', 'en_score': 78.1, 'math_scroe': 65.8}]
后三:[{'name': 'HanMeimei', 'en_score': 65.6, 'math_scroe': 86.9}, {'name': 'Bob', 'en_score': 72.4, 'math_scroe': 84.2}, {'name': 'Tracy', 'en_score': 72.6, 'math_scroe': 65.4}]
完美解决,没错,你没看错,都是一行代码!
So Easy!
heapq模块
上面的方法中nlargest()和nsmallest()函数的底层实现是:先将序列数据进行堆排序后放入一个列表中,本质上来讲也是多种方法的封装。
需要强调的是,当我们使用type查看上面的high和low的类型时,返回的是。因此,通过传入序列,此函数使用到了堆结构特性去处理该序列,而返回结果类型依然是该序列本身的类型。
对于一个堆heap的数据结构有以下优点:
heap[0]永远是最小的元素其余元素可通过调用 heapq.heappop()方法得到,该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是O(log N),N是堆大小)通过上面的描述,如果查找最小的三个元素,其实等价于分别从堆结构中使用heappop()方法弹出3个值即可。
我们先来详细了解下模块heapq提供的接口有哪些……
如何使用
【如何创建堆】
方法一:使用heappush()方法
heap = []
data = [2,3,5,7,9,23,14,16,12,10]
for i in data:
heapq.heappush(heap,i)
>>>print(heap)
[2, 3, 5, 7, 9, 23, 14, 16, 12, 10]
此时,其实并没有进行排序
方法二:使用heapify()方法
data = [2,3,5,7,9,23,14,16,12,10]
heapq.heapify(data)
此时,直接变换data数据为堆结构,并没有返回新的数据
【堆如何排序】
如何排序
方法一:
使用heapq.nlargest()和heapq.nsmallest()方法即可实现。
heapq.nXXXest(num, set, key)
num:表示返回数据的个数
set:表示要处理的序列(当然集合最好,没有重复元素)
key:表示排序规则
方法二:
我们使用heappop()可以弹出heap中的数据。此时,弹出的数据就是排序后的数据。
lst = []
while heap:
lst.append(heapq.heappop(heap))
>>>print(lst)
[2, 3, 5, 7, 9, 10, 12, 14, 16, 23]
怎么样,是不是很神奇?
能读到这里,说明你真的喜欢Python,想学习点干货,看下面……
各种排序场合应用
对heapq使用场合给出几点建议:
好东西分享给大家
查找(排序)元素个数相对序列较小时,函数 nlargest()和 nsmallest()是最佳选择;查找序列唯一的最小、最大的元素,推荐使用min()和max()函数最快。查找(排序)元素个数和序列个数接近时,先排序、再切片,这样会更快。
一个问题
创建一个简单堆,使用heapify(lst)即可。
大家自己解决
如果需要把复杂的列表,如上面的scoreInfo直接传入heapify(scoreInfo)这样是会抛出异常的,异常信息为:
“TypeError: '
这个该如何解决呢?小伙伴们有没有好办法实现?欢迎下方留下宝贵意见。
好了,今天的内容就到这里了,我们通过一个简单的排序案例,讲解了利用堆结构排序的方法。小伙伴们Get到这个技能了吗?上面的问题有没有小伙伴会的?希望不吝赐教,大家共同学习进步。喜欢Python编程的小伙伴关注我,后续有更加精彩的内容推出。
转载请注明出处,百家号:Python高手养成