Loops
Why we need loops
Analogy
- Say you have to print "Hello" a hundred times. You could write the line a hundred times. It would work.
- Then someone asks for a thousand, and you would quietly change career.
- A loop is how you say do this again without writing it again. Change 100 to 1,000,000 and the code does not get any longer.
- And this is not about saving keystrokes. Almost every useful program is a loop over something: every row in a spreadsheet, every message in an inbox, every item in a list you are about to sort.
What is a loop?
Definition
A loop repeats a block of work while a condition holds.
Whatever the language and whatever the syntax, a loop is always the same four things: a start, a condition checked before every round, a body that does the work, and an update that moves you closer to stopping.
If a loop misbehaves, one of those four is wrong. Check them in that order.
Notice where start sits. It runs once, outside the ring. A beginner who thinks it runs every round has written the infinite loop where the counter gets reset at the top of the body.
Which loop to use
| Situation | Loop |
|---|---|
| A known number of rounds | for |
| Every item in a list | for-each |
| Repeat until something changes | while |
| Must run at least once | do-while |
for when the number of rounds is known before you start. The Java form shows all four parts on one line: for (int i = 0; i < 5; i++) is start, condition and update, with the body in braces.
for-each when you want each item and do not care about its position. No counter, no index, nothing to get wrong. Prefer it whenever you do not actually need the index.
while when you are waiting for something to become true and cannot predict how long that takes.
i = 0while i < 5: print(i) i += 1 # forget this line and it never endsA for loop keeps its four parts together in one place. A while loop scatters them, so you have to remember the update yourself. That is exactly why beginners write more infinite loops with while.
do-while checks the condition at the bottom, so the body always runs at least once. Perfect for menus: you always want to show the menu once before asking whether to show it again. Python has no do-while; the standard workaround is while True with a break at the bottom.
Why counting starts at zero
Because array positions start at 0. The first item is at index 0, and the last item in a list of five is at index 4. Starting your counter at 0 lines the two up perfectly.
Get used to it now, because it never goes away - and it is the source of the most common loop bug there is.
Off-by-one
Watch out
A list of three items has positions 0, 1 and 2. The length is 3 and the last valid position is 2.
for i in range(len(items)): # 0, 1, 2. correctfor i in range(len(items) + 1): # 0, 1, 2, 3. crashIn C-style languages the same trap wears a different mask: i <= n does one round too many where i < n is correct.
The habit that saves you: whenever you write a loop, say out loud what the first value and the last value will be. Two seconds of checking prevents most of these.
break and continue
break leaves the loop entirely. Nothing after it in this round runs, and no further rounds happen. continue skips the rest of this round and jumps to the next one.
for item in items: if item == target: print("Found it") break # stop searching, we are doneBoth are useful. Both, used heavily, make a loop hard to follow. One break for an early exit is good; five scattered through a long body is a mess. And break only ever leaves the innermost loop.
Nested loops, and where slow code is born
A loop inside a loop. The inner one completes fully for every single round of the outer one, so three rounds outside and four inside is twelve.
Note
One loop over n items does n steps. A loop inside a loop does n × n.
The difference is brutal. With 1,000 items, one loop is 1,000 steps and a nested loop is 1,000,000.
When you meet bubble sort and see the phrase "O(n squared)", this is all it means: two nested loops over the same data.
Mistakes to watch for
Watch out
- Forgetting the update in a
while, creating an infinite loop. - Off-by-one. Using
<=where you needed<. - Changing a list while looping over it. Items get skipped. Loop over a copy instead.
- Assuming
breakexits all loops. It exits only the innermost one. - Putting work inside a loop that could sit outside it, doing the same job a thousand times.
- Confusing
breakandcontinue. One leaves, one skips.
Quick recap
- A loop repeats work without repeating code
- Every loop is start, condition, body, update
forfor a known count,for-eachfor items,whilefor an unknown countbreakleaves the loop,continueskips to the next round- Infinite loops usually mean a missing or wrong update
- Indexes start at 0, so the last one is length minus one
- Nested loops cost n times n, and that is where slow code begins
Key takeaway
Start, condition, body, update. Every loop is those four, and every loop bug is one of them.