PythonMastery

Get the top few with heapq.nlargest, not a full sort

To get the 5 biggest orders you don't need all million in order. heapq.nlargest keeps only the top N as it reads, with a key= just like sorted().

"The five most expensive orders" and "the three slowest requests" are top-N questions. Sorting the whole list answers them, but it puts every item in order just to read the first few. heapq.nlargest and nsmallest keep only the N you asked for.

Before

python
orders = [("A-1", 120.0), ("A-2", 15.5), ("A-3", 980.0), ("A-4", 42.0),
          ("A-5", 610.0), ("A-6", 7.25), ("A-7", 305.0)]

top3 = sorted(orders, key=lambda o: o[1], reverse=True)[:3]
print(top3)
output
[('A-3', 980.0), ('A-5', 610.0), ('A-7', 305.0)]

After

python
import heapq

orders = [("A-1", 120.0), ("A-2", 15.5), ("A-3", 980.0), ("A-4", 42.0),
          ("A-5", 610.0), ("A-6", 7.25), ("A-7", 305.0)]

print(heapq.nlargest(3, orders, key=lambda o: o[1]))
print(heapq.nsmallest(2, orders, key=lambda o: o[1]))
output
[('A-3', 980.0), ('A-5', 610.0), ('A-7', 305.0)]
[('A-6', 7.25), ('A-2', 15.5)]

Same answer, and it says what you meant: the largest three, not "sort, reverse, slice".

Measure it

On a big list the difference shows. Run this; the numbers are from your machine.

python
import heapq, random, timeit

random.seed(7)
prices = [random.uniform(1, 1000) for _ in range(200_000)]

t_sort = timeit.timeit(lambda: sorted(prices, reverse=True)[:5], number=5) / 5
t_heap = timeit.timeit(lambda: heapq.nlargest(5, prices), number=5) / 5
print(f"sorted: {t_sort * 1000:.1f} ms   nlargest: {t_heap * 1000:.1f} ms")
print(f"nlargest was about {t_sort / t_heap:.0f}x faster")
example output · yours will differ
sorted: 26.8 ms   nlargest: 3.0 ms
nlargest was about 9x faster

Why it works

nlargest(5, ...) keeps a small heap of the best five seen so far. Each new item is compared with the smallest of those five and usually thrown away straight off. Sorting has to place every one of the 200,000 items.

When not to use it

When N is close to the size of the list, a plain sorted() is as fast or faster; the docs suggest sorting once N is large. For the single biggest or smallest item, max() and min() (both take key= too) are simpler still. And if you need the top N repeatedly from data that keeps changing, keep a real heap with heapq.heappush rather than calling nlargest each time.

Learn it properly: Lists & Sequences, Performance: Profile, Then Optimise