如何查找序列中最大的N個元素,Python模塊heapq的使用方法及場合

2021-01-11 python高手養成

今天的內容很簡單,我們有一個序列,如何找到該序列中最大或者最小的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的類型時,返回的是<class 'list'>。因此,通過傳入序列,此函數使用到了堆結構特性去處理該序列,而返回結果類型依然是該序列本身的類型。

對於一個堆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: '<' not supported between instances of 'dict' and 'dict'」

這個該如何解決呢?小夥伴們有沒有好辦法實現?歡迎下方留下寶貴意見。

好了,今天的內容就到這裡了,我們通過一個簡單的排序案例,講解了利用堆結構排序的方法。小夥伴們Get到這個技能了嗎?上面的問題有沒有小夥伴會的?希望不吝賜教,大家共同學習進步。喜歡Python編程的小夥伴關注我,後續有更加精彩的內容推出。

轉載請註明出處,百家號:Python高手養成

相關焦點

  • Python數據類型串講(中)
    x='python 'print(x*3)以上代碼執行結果為:元素存在判斷使用python的關鍵字「in」或「not in」,可以判斷指定元素是否存在該序列中或是否不存在該序列中,滿足條件則返回True ,不滿足條件則返回False 。
  • 使用Python和C語言實現二分法查找(折半查找)
    二分查找 叫折半查找,它對要查找的序列有兩個要求,一是該序列必須是有序的,二是該序列必須是順序存儲的。二分法查找算法的原理如下:1、 如果待查對象為空返回-1,表示查找不到目標元素2、 如果待查序列不為空,則將中間元素與要查找的目標元素進行匹配看是否相等,如果相等表示 查找成功,返回該中間元素的索引如果不相等再比較這兩個元素的大小
  • python隨機模塊22個函數詳解(上)
    作者:小伍哥來源: AI入門學習今天給大家介紹下python中的隨機模塊,隨機數可以用於數學,遊戲,安全等領域中,還經常被嵌入到算法中,用以提高算法效率,並提高程序的安全性。平時數據分析各種分布的數據構造也會用到。
  • 玩轉Python 中的隨機數
    隨機生成 0 到 1 之間的浮點數random.random() 方法會返回 [0.0, 1.0) 之間的浮點數,注意,這是一個左閉右開的區間,隨機數可能會是 0 但不可能為 1 。隨機生成 a 與 b 之間的整數使用 random.randint(a , b) 方法,你可以生成一個 a 與 b 之間的隨機整數,也就是 [a, b] 。
  • 序列比對在biopython中的處理
    序列比對是生物信息學分析中的常見任務,包含局部比對和全局比對兩大算法,局部比對最經典的代表是blast, 全局比對則用於多序列比對。在biopython中,支持對序列比對的結果進行讀寫,解析,以及運行序列比對的程序。
  • python sys模塊的常見用法匯總
    python的內置模塊sys,提供了系統相關的一些變量和函數,在實際開發中,常見的有以下幾種用法1.版本有限制的代碼,可以通過以上方法來判斷python版本是否符合要求。6. sys.path該變量存儲了python尋找模塊的路徑
  • python正則表達式使用方法說明
    曾光紅/文 (同步發布豆瓜網)一、導入re庫python使用正則表達式要導入re庫。import re在re庫中。正則表達式通常被用來檢索查找、替換那些符合某個模式(規則)的文本。三、正則表達式中常見的基本符號1.點號「.」一個點號可以代替除了換行符(\n)以外的任何一個字符,包括但不限於英文字母、數字、漢字、英文標點符號和中文標點符號。
  • Python語言中使用array模塊實現動態數組的操作
    背景對於動態數組諸如創建、插入、刪除、查詢大小等操作,在C/C++語言中,可以使用標準庫中的vector類實現,而在python語言中,也同樣提供了內置的array模塊實現類似的功能。Python中的array類似於列表list,如都可以動態增刪元素,但又有所區別,list中存儲的元素類型可以不一樣,但array中元素類型必須完全一樣。另外,由於list中每個元素同時存儲了其地址即指針(用以標記每個元素的數據類型)和實際的數據,所以,在存儲及操作效率上,array又遠遠高於列表。下面通過例子講解array模塊的常用操作。
  • python+=和排序
    dis模塊主要是用來分析字節碼的一個內置模塊,經常會用到的方法是dis.dis([bytesource]),參數為一個代碼塊,可以得到這個代碼塊對應的字節碼指令序列。#可選參數key 還可以在內置函數min() 和max() 中起作用。另外,還有些標準庫裡的函數也接受這個參數,像itertools.groupby() 和heapq.nlargest() 等。#Python 的排序算法——Timsort——是穩定的,意思是就算兩個元素比不出大小,在每次排序的結果裡它們的相對位置是固定的。
  • 二分查找會更快嗎?Python中的二分查找與線性查找性能測試
    當您要檢查某個元素是否在列表中時,有很多方法可以解決相同的問題。可以通過線性查找和二分查找來完成,但是要猜測哪個更快。為什麼?如果你最近參加過面試,你就會知道二分查找是面試官的最愛。您為什麼要花時間學習二分查找? C ++編程朋友可能已經告訴過您。 Python很慢。 您想確保自己的程序不會比所需的速度慢。
  • Python學習第112課——numpy中數組查找元素和改變元素的小技巧
    【每天幾分鐘,從零入門python編程的世界!】上節我們學習了如何利用index找到ndarray數組中的一些元素,並把找到的元素生成一個新的ndarray。代碼如下:現在我們學習幾個用index找到ndarray中元素的小技巧。
  • 使用機器學習和Python揭開DNA測序神秘面紗
    Biopython是python模塊的集合,這些模塊提供處理DNA,RNA和蛋白質序列操作的功能,例如DNA字符串的反向互補,尋找蛋白質序列中的基序列等。因此,使用上述方法,您必須輔助諸如截斷序列或用「 n」/「 0」填充的方法,以獲取長度一致的向量。DNA和蛋白質序列可以看作是生命的語言。該語言對所有生命形式中存在的分子的指令和功能進行編碼。基因組與序列語言和書是相似的,子序列(基因和基因家族)是句子和章節,k-mers和肽是單詞,核苷酸鹼基和胺基酸是字母。
  • Python內置模塊math介紹
    # 導入模塊import math#dir(module):可以通過它查看任何模塊中所包含的工具
  • 三分鐘從入門到精通——Python模塊
    中的模塊:假設您正在使用python解釋器。您花了30分鐘來定義一個函數,然後使用它並退出解釋器。但是突然間,您記住仍然需要再次使用該功能。您再次輸入它,但該功能的定義已消失。哎呀,好痛。現在,您再次需要花費30分鐘來鍵入相同的功能。因此,python有一種方法可以將該函數定義放入文件中並隨時使用。模塊是ModuleType類型的對象。
  • python高階函數:map、filter、reduce的替代品
    map函數在小編以前的文章中做過相應的知識分享。sorted函數是python的內置函數,它的可選參數key用於提供一個函數,它可以將函數應用到各個元素上進行排序。根據單詞長度,使用sorted函數對一個列表進行排序。
  • 乾貨| 完美Python入門基礎知識點總結
    python的字串列表有2種取值順序從左到右索引默認0開始的,最大範圍是字符串長度少1從右到左索引默認-1開始的,最大範圍是字符串開頭List(列表) 是 Python 中使用最頻繁的數據類型列表可以完成大多數集合類的數據結構實現。
  • python基礎課程 第5章 奇妙的內建函數
    今天我們來講講 python 的常用內建函數,以便於大家在日常編程過程中遇到類似的場景可以直接拿來使用,不用再重複自己了。python 內建函數(python自帶的函數) 數量加起來大概有70多個,今天我們主要講常用的一些,至於更多的內容可以在以後的基礎教程裡慢慢學到。
  • Python使用ctypes模塊調用DLL函數之複數數組的參數傳遞
    這兒就涉及到了如何將C語言中的複數數組(Complex array)類型與Python中的數據類型進行交互的問題。在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,前面多篇文章中已經講了傳遞數值/指針/字符串參數、傳遞結構體參數、傳遞普通數組類型的例子,大家可以回看一下,這樣可以更好的理解本次要講的內容。
  • Python 爬蟲面試題 170 道:2019 版
    .如何打亂一個列表的元素?55.寫一個函數,接收整數參數 n,返回一個函數,函數的功能是把函數的參數和 n 相乘並把結果返回。56.下面代碼會存在什麼問題,如何改進?97.列舉 5 個 Python 中的標準模塊98.如何在函數中設置一個全局變量99.pathlib 的用法舉例100.Python 中的異常處理,寫一個簡單的應用場景101.Python 中遞歸的最大次數,那如何突破呢?
  • 代碼詳解:Python正則表達式的終極使用指南
    人們可能想要在文本中找出特定格式的內容,比如找出存在於文本中的電子郵件,或者大型文本中的電話號碼。雖然想要實現上述功能聽起來很繁瑣,但是如果使用Python正則表達式模塊,就可以使這一操作更加簡單。假設要在一篇特定的文章中找出標點符號的數量。以狄更斯的作品文本為例。你通常會怎麼做?