Linear Search
Linear search is the name for the obvious method: look at the first item, then the next, then the next, until you find what you want or run out of tuple. It is worth a page of its own because the careless version of it — decide the answer inside the loop — gets the wrong answer, and gets it in a way that looks right.
1Program 1 — is it there at all?
Ask whether a given mark appears anywhere in a tuple, and say so.
# is the wanted value in the tuple?
marks = (56, 91, 43, 78, 65)
wanted = 78
found = False
for m in marks:
if m == wanted:
found = True
if found:
print(wanted, 'is in the tuple')
else:
print(wanted, 'is not in the tuple')78 is in the tuple
60 is not in the tuple
found = FalseA collector again, and the value that means 'nothing yet' for a yes-or-no answer is False. Made above the loop, so it survives every round.
found = TrueSet once and never unset. The loop is allowed to say yes; it is never allowed to say no, because a later item that does not match proves nothing.
if found:The decision is taken AFTER the loop, when every item has had its turn. This is the line that matters.
if…else inside the loop and the program says “not in the tuple” four times and “is in the tuple” once — five answers to a question that has one. A search decides after the walk, not during it.2Program 2 — and where is it?
Report the position of the wanted value, or say it is absent.
Now the answer is a position, so the loop has to be the index form — and the flag becomes a number. -1 is the traditional stand-in for “nowhere”, because it is not a position any tuple has.
# where is the wanted value?
marks = (56, 91, 43, 78, 65)
wanted = 78
position = -1
for i in range(len(marks)):
if marks[i] == wanted:
position = i
if position == -1:
print(wanted, 'was not found')
else:
print(wanted, 'found at index', position)78 found at index 3
-1 and not 0? Because 0 is a real position — the first one. A program that used 0 to mean “not found” could never tell you that the answer was the very first item.3Program 3 — stopping the moment it is found
Program 2 keeps checking after it has the answer. On five marks that is nothing; on five thousand it is silly. break leaves the loop the instant the answer is known:
# stop as soon as it is found
marks = (56, 91, 43, 78, 65, 78)
wanted = 78
position = -1
for i in range(len(marks)):
print('checking index', i)
if marks[i] == wanted:
position = i
break
print('Found at index', position)checking index 0 checking index 1 checking index 2 checking index 3 Found at index 3
Indexes 4 and 5 are never looked at. Notice the side effect: this tuple holds 78 twice, and stopping early means the program reports the first one. Program 2, which never stops, would have reported the last. Neither is wrong — but they answer different questions, and you should know which one you asked.
4Program 4 — break with the loop's own else
A loop may carry an else, and it runs only when the loop finished without hitting a break. That is exactly the shape of a search, and it removes the flag entirely:
# no flag at all: else belongs to the for, not to the if
marks = (56, 91, 43, 78, 65)
wanted = 60
for i in range(len(marks)):
if marks[i] == wanted:
print(wanted, 'found at index', i)
break
else:
print(wanted, 'is not in the tuple')60 is not in the tuple
78 found at index 3
else lines up with for, not with if. Look at the indentation: it starts in the same column as for. Indent it to match the if instead and the program prints “is not in the tuple” once for every item that is not the one you want. Read the loop's else as “if no break happened”.5The built-in way — in and index()
# what you would write when the question does not forbid it
marks = (56, 91, 43, 78, 65)
print(78 in marks)
print(60 in marks)
print(marks.index(78))True False 3
in is the found flag and the whole loop, in two characters. index() is program 3 — it finds the first match and stops. But it has a temper:
marks = (56, 91, 43, 78, 65)
print(marks.index(60))Traceback (most recent call last):
File "index_error.py", line 3, in <module>
print(marks.index(60))
^^^^^^^^^^^^^^^
ValueError: tuple.index(x): x not in tuplein first, then index(). Ask whether it is there before asking where it is — that is the whole pattern, and it is two lines:# check first, then ask where
marks = (56, 91, 43, 78, 65)
wanted = 60
if wanted in marks:
print(wanted, 'found at index', marks.index(wanted))
else:
print(wanted, 'is not in the tuple')60 is not in the tuple
6Program 5 — searching a tuple of records
Given a tuple of (name, marks) rows, look up one student by name.
This is where in stops helping: you are not looking for a row, you are looking for a row whose first column matches. Only the loop can express that.
# look a student up by name
records = (('Riya', 78), ('Amit', 85), ('Sara', 62), ('John', 91))
wanted = 'Sara'
for name, marks in records:
if name == wanted:
print(wanted, 'scored', marks)
break
else:
print(wanted, 'is not on the list')Sara scored 62
Kabir is not on the list
7Program 6 — every position it appears at
index() gives you the first and nothing else. When all of them are wanted, there is no built-in — just the loop with no break in it:
# every place the value turns up
marks = (78, 91, 43, 78, 65, 78)
wanted = 78
for i in range(len(marks)):
if marks[i] == wanted:
print('found at index', i)found at index 0 found at index 3 found at index 5
8Recap
found = False above, found = True inside, the if…else after. Putting the else inside gives one answer per item.
0 cannot mean it, because 0 is a real position — the first one.
Without break the loop reports the last match instead. Both are valid; know which question you asked.
It lines up with for, not with if, and it replaces the found flag entirely.
index() raises ValueError when the value is absent, so it is only safe once in has said yes.
'Sara' in records is False — records holds rows, not names. Unpack the row and compare the column you mean.
- 1
Search a tuple of names for one typed in with
input(), and report whether it is there.Hint · The found-flag program. Watch the case —
'riya'and'Riya'are different strings, so compare.lower()to.lower(). - 2
Count how many times a value appears, without
count().Hint · Same walk, but a counter instead of a flag — and no
break, because every match has to be seen. - 3
Report the last position a value appears at.
Hint · Program 2 without a
break: later matches simply overwriteposition. - 4
From a tuple of
(city, pin)rows, look up the PIN code for a city.Hint · Program 5 with the columns renamed, and the
for…elsefor the city that is not on the list.
Why does the if…else belong after the loop rather than inside it?
What does the else attached to a for loop mean?
Why is marks.index(60) risky on its own?