1. 程式人生 > >python-進階教程-heapq模組

python-進階教程-heapq模組

0.摘要

本文主要介紹heapq模組提供的主要函式方法。

 

1.nlargest()和nsmallest

從字面意思就可以知道

heapq.nlargest(n, iterable, key=None) :返回可列舉物件中的 n 個最大值
heapq.nsmallest(n, iterable, key=None) :返回可列舉物件中的 n 個最小值。

import heapq

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(heapq.nlargest(3,nums))
print(heapq.nsmallest(3,nums))
#result:[9, 8, 7]
#result:[0, 1, 2]

相比於max()和min()函式,nlargest()和nsmallest()能夠按遞增或遞減順序給出最大或最小的n個值

另外,nlargest()和nsmallest()更強大的地方在於能夠接受一個引數key,從而允許了這兩個函式能夠工作在更為複雜的資料結構上。

import heapq

portfolio = [
   {'name': 'IBM', 'shares': 100, 'price': 91.1},
   {'name': 'AAPL', 'shares': 50, 'price': 543.22},
   {'name': 'FB', 'shares': 200, 'price': 21.09},
   {'name': 'HPQ', 'shares': 35, 'price': 31.75},
   {'name': 'YHOO', 'shares': 45, 'price': 16.35},
   {'name': 'ACME', 'shares': 75, 'price': 115.65}
]

cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])

print(cheap)
print(expensive)
#result:[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
#result:[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]

通過key引數,可以以字典中的某個量為依據,找出最大或最小的n個值。

注意:key引數並非一定是數值,字串也同樣可以(按照ASCII碼排序)。

提示:max()和min()函式也具有key引數,這裡替換為max()和min()函式即可得到最大和最小的值。

 

2.heappush()和heappop

heapq.heappush(heap, item):將元素新增到heap中
heapq.heappop(heap):返回 root 節點,即 heap 中最小的元素

使用heappush()和heappop實現一個優先佇列例子,即每次pop操作,彈出的是優先順序最大的與元素。

注意:heapq.heappop()彈出的是優先順序最小的元素,這裡通過對優先順序取相反數顛倒優先順序。

import heapq

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self, item, priority):
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1

    def pop(self):
        return heapq.heappop(self._queue)[-1]

# Example use
class Item:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Item({!r})'.format(self.name)

q = PriorityQueue()
q.push(Item('foo'), 1)
q.push(Item('bar'), 5)
q.push(Item('spam'), 4)
q.push(Item('grok'), 1)

print("Should be bar:", q.pop())
print("Should be spam:", q.pop())
print("Should be foo:", q.pop())
print("Should be grok:", q.pop())
#result:Should be bar: Item('bar')
#result:Should be spam: Item('spam')
#result:Should be foo: Item('foo')
#result:Should be grok: Item('grok')

這裡引入index是為了防止優先順序相同的情況,根據index進行排序。

元組(-priority, item)在priority相同的情況下,元組會對item進行比較。

但是,Item例項在python中是不能進行比較運算的,強制比較會導致報錯。

加入index就可以避免這一問題,因為每一個元素的index都是不同的。這樣,在priority相同的情況下,會比較index大小,並且由於index必然不相等,所以不存在進一步比較item的情況,從而避免了報錯。