Sorting, Searching & Counting
Reviewed & published by Brayan K
Sorting, searching, and counting are the tools for putting array data in order and finding out what's inside it — NumPy provides fast, vectorized functions like np.sort, np.argsort, np.searchsorted, and np.unique for exactly this.
Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll order arrays, learn copy-vs-in-place sorting, get sort indices, search sorted data, and count values and non-zeros.
What You'll Learn in This Lesson
- np.sort (copy) vs arr.sort() (in place)
- np.argsort for the sorting indices
- Sorting a 2D array along an axis
- Fast lookups with np.searchsorted
- Unique values and counts with np.unique
- Counting with np.count_nonzero and argmax/argmin
1 np.sort (copy) vs arr.sort() (in place)
np.sort(arr) returns a new sorted copy and leaves the original untouched. The method arr.sort() sorts in place — it changes the original array and returns None. Choosing the right one avoids surprising bugs.
import numpy as np
original = np.array([3, 1, 2])
# np.sort returns a new copy; original is unchanged
copy_sorted = np.sort(original)
print(copy_sorted) # [1 2 3]
print(original) # [3 1 2] -> still original order
# arr.sort() sorts in place and returns None
original.sort()
print(original) # [1 2 3] -> now changed
# ✅ Expected output:
# [1 2 3]
# [3 1 2]
# [1 2 3]Expected output: [1 2 3], then the original still [3 1 2], and finally [1 2 3] after the in-place sort.
2 Sort Indices: np.argsort
np.argsort(arr) returns the indices that would sort the array. Indexing the array with those indices gives the sorted values — and the same indices can reorder a parallel array, which is how you sort one list by another (e.g. sort names by their scores).
import numpy as np
scores = np.array([50, 90, 70])
names = np.array(["Ann", "Bob", "Cara"])
order = np.argsort(scores)
print(order) # [0 2 1] -> positions of smallest to largest
print(scores[order]) # [50 70 90]
print(names[order]) # ['Ann' 'Cara' 'Bob'] -> names sorted by score
# ✅ Expected output:
# [0 2 1]
# [50 70 90]
# ['Ann' 'Cara' 'Bob']Expected output: [0 2 1], then [50 70 90], then ['Ann' 'Cara' 'Bob'].
3 Sorting a 2D Array Along an Axis
For 2D arrays, the axis argument controls the direction. axis=1 sorts each row left to right; axis=0 sorts each column top to bottom. The default is the last axis.
import numpy as np
grid = np.array([[3, 1, 2],
[9, 7, 8]])
print(np.sort(grid, axis=1)) # sort each row (left to right)
# [[1 2 3]
# [7 8 9]]
print(np.sort(grid, axis=0)) # sort each column (top to bottom)
# [[3 1 2]
# [9 7 8]]
# ✅ Expected output:
# [[1 2 3]
# [7 8 9]]
# [[3 1 2]
# [9 7 8]]Expected output: rows sorted to [[1 2 3] [7 8 9]], and columns already in order so axis=0 leaves [[3 1 2] [9 7 8]] unchanged.
4 Searching (searchsorted) & Counting (unique, count_nonzero)
np.searchsorted(sorted_arr, value) uses binary search to find the index where value would be inserted to keep the array sorted. For counting, np.unique(arr, return_counts=True) returns the sorted unique values and how often each appears, np.count_nonzero counts non-zero (or True) elements, and np.argmax / np.argmin return the index of the largest / smallest value.
import numpy as np
sorted_arr = np.array([10, 20, 30, 40, 50])
# Where would 25 go to keep things sorted?
print(np.searchsorted(sorted_arr, 25)) # 2
# You can search for many values at once:
print(np.searchsorted(sorted_arr, [5, 35, 60])) # [0 3 5]
# ✅ Expected output:
# 2
# [0 3 5]Expected output: 2 (25 fits between 20 and 30), then [0 3 5] for the three queries.
import numpy as np
votes = np.array(["a", "b", "a", "c", "a", "b"])
values, counts = np.unique(votes, return_counts=True)
print(values) # ['a' 'b' 'c']
print(counts) # [3 2 1]
nums = np.array([0, 5, 0, 8, 3])
print(np.count_nonzero(nums)) # 3 -> three non-zero values
print(np.count_nonzero(nums > 4)) # 2 -> two values greater than 4
print(np.argmax(nums)) # 3 -> index of the max (8)
print(np.argmin(nums)) # 0 -> index of the min (0)
# ✅ Expected output:
# ['a' 'b' 'c']
# [3 2 1]
# 3
# 2
# 3
# 0Expected output: values ['a' 'b' 'c'] with counts [3 2 1], then 3, 2, 3, 0.
🎯 YOUR TURN: Fill in the Blanks
Replace each ___ so the program prints a sorted copy and the unique values with their counts.
import numpy as np
data = np.array([2, 1, 2, 3, 1, 2])
print(np.___(data)) # fill in: sorted copy -> [1 1 2 2 2 3]
values, counts = np.unique(data, return_counts=___) # fill in: True
print(values) # [1 2 3]
print(counts) # [2 3 1]Expected output: [1 1 2 2 2 3], then [1 2 3] and [2 3 1]. (Answers: sort, True.)
⚠️ Common Errors & Quick Reference
❌ arr = arr.sort() gives None
arr.sort() sorts in place and returns None, so assigning it wipes out your array.
✅ Fix: call arr.sort() alone, or use arr = np.sort(arr) for a copy.
❌ Confusing argmax with max
np.argmax returns the index of the largest value, not the value itself.
✅ Fix: use arr.max() for the value, np.argmax(arr) for its position.
| Task | Code |
|---|---|
| Sorted copy | np.sort(arr) |
| Sort in place | arr.sort() |
| Sort indices | np.argsort(arr) |
| Insertion point | np.searchsorted(arr, v) |
| Unique + counts | np.unique(arr, return_counts=True) |
| Count non-zeros | np.count_nonzero(arr) |
🏆 Mini Challenge: Top 3 Scores
Given test scores, find the three highest and the index of the very best, using sorting and argmax.
import numpy as np
scores = np.array([55, 92, 78, 88, 64, 99])
# Sort ascending, take the last 3, reverse for top-down
top3 = np.sort(scores)[-3:][::-1]
print(top3) # [99 92 88]
print(np.argmax(scores)) # 5 -> index of the single best score
print(np.count_nonzero(scores >= 70)) # 4 -> passing scores (>= 70)
# ✅ Expected output:
# [99 92 88]
# 5
# 4Expected output: [99 92 88], then 5, then 4 passing scores.
❓ Frequently Asked Questions
Lesson complete — you can order and analyze data!
You learned copy-vs-in-place sorting, np.argsort, axis sorting, np.searchsorted, and the counting tools np.unique, np.count_nonzero, and argmax/argmin.
Practice quiz
What does np.sort(arr) do?
- Returns a new sorted copy, leaving the original unchanged
- Sorts the original in place
- Returns None
- Reverses the array
Answer: Returns a new sorted copy, leaving the original unchanged. np.sort returns a brand-new sorted copy and leaves the original untouched.
What does the method arr.sort() return?
- A sorted copy
- None (it sorts in place)
- The indices
- The original order
Answer: None (it sorts in place). arr.sort() sorts in place and returns None, so arr = arr.sort() destroys your data.
What does np.argsort(arr) return?
- The sorted values
- The maximum
- The indices that would sort the array
- The counts
Answer: The indices that would sort the array. argsort returns the indices that would sort the array, useful for sorting a parallel array.
Which axis sorts each row of a 2D array left to right?
- axis=0
- axis=None
- axis=2
- axis=1
Answer: axis=1. axis=1 sorts along the columns within each row (left to right).
What does np.searchsorted do?
- Finds the insertion index to keep a sorted array sorted
- Sorts in reverse
- Counts elements
- Removes duplicates
Answer: Finds the insertion index to keep a sorted array sorted. searchsorted uses binary search to find where a value would be inserted to stay sorted.
How do you get unique values with their counts?
- np.sort(arr)
- np.unique(arr, return_counts=True)
- np.argsort(arr)
- np.count_nonzero(arr)
Answer: np.unique(arr, return_counts=True). np.unique with return_counts=True returns sorted unique values and their counts.
What does np.argmax(arr) return?
- The maximum value
- The sum
- The index of the largest value
- The sorted array
Answer: The index of the largest value. argmax returns the index of the largest value, not the value itself.
What does np.count_nonzero(arr > 4) count?
- The total elements
- The maximum
- The first index
- How many elements are greater than 4
Answer: How many elements are greater than 4. Applied to a boolean mask, count_nonzero counts the True elements, i.e. those greater than 4.
Why prefer np.sort(arr) when you must keep the original order?
- It returns a copy and leaves the original intact
- It is faster
- It sorts in reverse
- It removes duplicates
Answer: It returns a copy and leaves the original intact. np.sort produces a new array, so the original ordering is preserved.
What does arr.max() give compared to np.argmax(arr)?
- The index, while argmax gives the value
- Nothing different
- The value, while argmax gives its index
- Both give the index
Answer: The value, while argmax gives its index. arr.max() returns the value; np.argmax returns its position.
Continue this course
- Previous: Conditions: where, select, clip
- Next: Structured & Record Arrays — Store tabular data with named, typed fields in one array
- Quick reference: NumPy cheat sheet
Frequently asked questions
What is the difference between np.sort and arr.sort()?
np.sort(arr) returns a brand-new sorted copy and leaves the original array untouched. The method arr.sort() sorts the array in place and returns None, modifying the original. Use np.sort when you need to keep the original order.
What does np.argsort return?
np.argsort returns the indices that would sort the array, not the sorted values themselves. Indexing the original array with those indices gives you the sorted data, and the same indices can reorder a parallel array — handy for sorting one array by another.
How do I count how many times each value appears?
Use np.unique(arr, return_counts=True). It returns two arrays: the sorted unique values and how many times each one occurs. It is the standard way to build a frequency table in NumPy.
What is np.searchsorted used for?
np.searchsorted finds the index where a value could be inserted into a sorted array to keep it sorted. It uses binary search, so it is very fast, and it is great for bucketing or looking things up in sorted data.