Python Tutorial
Linear Search
The simplest search: check each element in turn until you find the target or run out.
How It Works
Linear (sequential) search walks the collection from the start, comparing each element to the target. It returns the position on the first match, or a sentinel (like −1) if the value is absent. No ordering is required — it works on any list.
| Case | Comparisons | Time |
|---|---|---|
| Best (first element) | 1 | O(1) |
| Average | n/2 | O(n) |
| Worst (last / absent) | n | O(n) |
Implementation
def linear_search(arr, target):
for i, value in enumerate(arr):
if value == target:
return i # found: return index
return -1 # not found
data = [64, 34, 25, 12, 22, 11, 90]
print(linear_search(data, 22)) # 4
print(linear_search(data, 99)) # -1Finding All Matches
def find_all(arr, target):
return [i for i, v in enumerate(arr) if v == target]
print(find_all([1, 3, 3, 7, 3], 3)) # [1, 2, 4]Pythonic Equivalents
In everyday code you rarely write the loop yourself — Python has built-ins that do linear search under the hood:
data = [64, 34, 25, 12]
print(25 in data) # True -> membership test
print(data.index(25)) # 2 -> raises ValueError if absent
# safe index lookup
idx = data.index(25) if 25 in data else -1If you search the same list many times, convert it to a set once (O(n)) and then test membership in O(1) each time instead of repeated O(n) scans.
When to Use Linear Search
- The data is small.
- The data is unsorted and sorting first is not worth it.
- You need every match, not just the first.
- The structure only allows sequential access (e.g. a linked list, a stream).
If the data is sorted and you search it often, binary search (next lesson) is dramatically faster at O(log n).
Best Practices
- Return a clear "not found" signal (−1 or
None) and document it. - Use
enumerateto get index and value together. - Prefer sets/dicts for repeated lookups; prefer binary search for sorted data.
Try It Yourself
Exercise 1: Return the index of the first negative number in a list, or −1.
Show solution
def first_negative(a):
for i, v in enumerate(a):
if v < 0:
return i
return -1
print(first_negative([3, 5, -2, 8])) # 2Exercise 2: When is linear search the right choice over binary search?
Show solution
When the data is unsorted, small, or you need every match — binary search requires sorted data.
📘 Real-World Deep Dive
Knowing <strong>DSA Linear Search (algorithms & data structures)</strong> well is what turns algorithms & data structures from a curiosity into a daily tool — you'll reach for it in nearly every real project.
Real-Life Scenario
An end-to-end usage of DSA Linear Search that you'd actually see in a data pipeline or analytics notebook.
Real-Life Example
def find(xs, target):
for i, x in enumerate(xs):
if x == target: return i
return -1
print(find([4, 1, 7, 3, 9], 7))
print(find([4, 1, 7, 3, 9], 8))Expected Output
(see source)Common mistakes
- Off-by-one errors in binary-search: the standard idiom is
while lo <= hiwithmid = (lo + hi) // 2. - Recursive algorithms blow the stack for n > ~10⁴; convert to iterative with an explicit stack.
- Comparison algorithms (
sorted(iterable)) are stable by default in Python — surprising for Java/C++ users. - Treating DSA Linear Search as a black box without reading the docs — the API has subtle defaults that bite when you scale.
🚀 Performance & Best Practices
- Use
bisect.bisect_left/bisect_rightinstead of writing your own binary search. - Convert a sorted search into a tuple-access pattern with
numpy.searchsortedfor huge arrays. - Use
heapqfor priority queues instead of maintaining a sorted list manually. - When working with algorithms & data structures, prefer vectorised / batched operations over Python loops.
🧪 Try It Yourself
- Reproduce the snippet on a representative slice of your own data.
- Profile the snippet with
cProfileortimeitand find the single biggest improvement. - Generalise the snippet into a small, reusable function you can drop into future projects.