To find the N largest or N smallest items of a collection in Python, we call heapq.nlargest(n, iterable) or heapq.nsmallest(n, iterable), which return a new list sorted from the most to the least extreme item. Both functions accept a key argument for records such as dictionaries, and they are much faster than sorting the whole collection when N is small.
import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
top3 = heapq.nlargest(3, nums) # [42, 37, 23]
bottom3 = heapq.nsmallest(3, nums) # [-4, 1, 2]
The sections cover the syntax and return value, simple and complex iterables, ties, and the speed against sorted(), max() and NumPy, with timings measured on Python 3.14. For the single largest item, see Python max() and min().
1. Syntax and Return Value
Both functions live in the heapq module of the standard library.
heapq.nlargest(n, iterable, key=None) -> list
heapq.nsmallest(n, iterable, key=None) -> list
- n is the number of items to return. A value of 0 or less returns an empty list, and a value larger than the input returns all items.
- iterable is any iterable, including generators and files, and it is read only once.
- key is an optional function that extracts the value to compare, as in sorted().
- Return value is a new list. nlargest() orders it from largest to smallest and nsmallest() from smallest to largest. The input is not changed.
2. Using heapq Module’s nlargest() and nsmallest()
The functions work on plain values and on records alike.
2.1. Find Items in Simple Iterables
For numbers or strings, the items themselves are compared. Duplicate values count as separate items, so 23 appears twice in a top 4.
import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
top4 = heapq.nlargest(4, nums) # [42, 37, 23, 23]
low2 = heapq.nsmallest(2, nums) # [-4, 1]
too_many = heapq.nlargest(20, [3, 1, 2]) # [3, 2, 1], all items
words = heapq.nsmallest(2, ["pear", "fig", "apple"]) # ['apple', 'fig']
2.2. Find Items in Complex Iterables
For dictionaries or objects, the key function selects the field to compare. The result contains the whole records.
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"])
cheap_names = [s["name"] for s in cheap] # ['YHOO', 'FB', 'HPQ']
expensive_names = [s["name"] for s in expensive] # ['AAPL', 'ACME', 'IBM']
The key can compute a value that is not stored in the record, such as the position size shares * price, and operator.itemgetter(“price”) is a faster alternative to the lambda.
biggest = heapq.nlargest(2, portfolio, key=lambda s: s["shares"] * s["price"])
biggest_names = [s["name"] for s in biggest] # ['AAPL', 'IBM']
2.3. Ties Keep the Input Order
When several items have the same key, the functions keep them in the order they appear in the input, like a stable sort.
import heapq
scores = [("ann", 90), ("bob", 95), ("cid", 90), ("dee", 90)]
top3 = heapq.nlargest(3, scores, key=lambda t: t[1])
# [('bob', 95), ('ann', 90), ('cid', 90)]
3. nlargest() vs sorted(), max() and NumPy
The heap functions win when N is small compared with the input, while a full sort wins when N is close to the input size. The documentation recommends min() and max() for N = 1 and sorted(iterable)[:n] for large N. Our timings on one million random floats with Python 3.14 confirm it.
| Method | N = 3 | N = 1,000 | N = 500,000 |
|---|---|---|---|
| heapq.nlargest(n, data) | 15 ms | 15 ms | 1,498 ms |
| sorted(data, reverse=True)[:n] | 308 ms | 259 ms | 316 ms |
For NumPy arrays, np.argpartition() finds the top N without sorting everything, which took 4 ms for N = 3 on the same data already stored as an array. Converting the list to an array adds about 30 ms. In pandas, Series.nlargest(n) and DataFrame.nlargest(n, “column”) do the same job.
import numpy as np
arr = np.array([1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2])
idx = np.argpartition(arr, -3)[-3:] # indexes of the 3 largest, unordered
top3_np = np.sort(arr[idx])[::-1] # array([42, 37, 23])
4. Real-World Example: Top Products from a Sales Log
A sales log can be long, and the report only needs the three best sellers and the slowest item. We count the units per product with a Counter and pick the extremes from its items.
import heapq
from collections import Counter
sales = [("tea", 3), ("milk", 1), ("tea", 2), ("jam", 5), ("bread", 4), ("milk", 1), ("honey", 1)]
units = Counter()
for product, qty in sales:
units[product] += qty
best = heapq.nlargest(3, units.items(), key=lambda kv: kv[1])
# [('tea', 5), ('jam', 5), ('bread', 4)]
slowest = heapq.nsmallest(1, units.items(), key=lambda kv: kv[1]) # [('honey', 1)]
Counter.most_common(3) returns the same top three and uses nlargest() internally. The most frequent element tutorial covers it.
5. nlargest() and nsmallest() FAQs
Readers ask about side effects, indexes and complexity.
5.1. Does nlargest() change the original list?
No. It reads the iterable and returns a new list. The functions heapq.heapify() and heapq.heappush() are the ones that rearrange a list in place.
5.2. How do we take items from a heap one at a time?
heapq.heapify() turns a list into a min-heap in place, and each heapq.heappop() call removes and returns the current smallest item. The priority queue tutorial builds on this.
import heapq
tasks = [5, 1, 4]
heapq.heapify(tasks)
first = heapq.heappop(tasks) # 1
second = heapq.heappop(tasks) # 4
5.3. How do we get the indexes of the N largest items?
We pass the indexes as the iterable and use the values as the key.
import heapq
values = [10, 50, 30, 50]
top_idx = heapq.nlargest(2, range(len(values)), key=values.__getitem__) # [1, 3]
5.4. What is the time complexity?
About O(m log N) for m input items and N results, because the functions keep a heap of N items. A full sort costs O(m log m), which is why the heap is faster for small N.
6. Conclusion
The heapq.nlargest() and heapq.nsmallest() functions return a sorted list of the N most extreme items, accept a key for records and keep ties in input order. They are the fastest choice for a small N, while max() and min() suit N = 1 and a full sorted() suits an N close to the input size.
7. References
Happy Learning !!