π Lesson 3.2: Loops β for and while
Why type the same thing a hundred times when you can tell the computer to do it for you? Loops are how programs handle repetition.
π― Learning Objectives
By the end of this lesson, you will be able to:
- Write
forloops in all three languages (counting-style and collection-style) - Understand Python's
range()vs. the classicfor (init; cond; step)pattern in JS/C# - Use
whileloops for condition-driven repetition - Control loop flow with
breakandcontinue - Recognize when to use
forvs.while
Estimated Time: 45 minutes
Project: A multiplication table generator and a number-guessing game
π In This Lesson
Why Loops?
Imagine you need to print the numbers 1 through 1000. Without loops, that's 1000 print statements. With a loop, it's three lines. Loops let your code repeat a block of instructions as many times as needed β whether that's a fixed count, once for each item in a list, or until some condition changes.
to process?"} B -->|Yes| C["Do the work"] C --> D["Move to next item"] D --> B B -->|No| E["Done!"] style B fill:#f59e0b,stroke:#d97706,color:#fff,stroke-width:2px style C fill:#10b981,stroke:#059669,color:#fff,stroke-width:2px
There are two main flavors of loops:
forloops β best when you know how many times to repeat (or are iterating over a collection)whileloops β best when you repeat until a condition becomes false
Counting for Loops
The most common loop: do something a specific number of times. This is where the three languages diverge most.
# Python: for + range()
# range(1, 6) produces 1, 2, 3, 4, 5 (start inclusive, stop exclusive)
for i in range(1, 6):
print(i)
# range() with one argument starts at 0:
# range(5) β 0, 1, 2, 3, 4
# range() with three arguments adds a step:
# range(0, 10, 2) β 0, 2, 4, 6, 8 (count by 2s)
# range(10, 0, -1) β 10, 9, 8, ... 1 (count backwards)
// JavaScript: classic three-part for loop
// for (initialize; condition; update)
for (let i = 1; i <= 5; i++) {
console.log(i);
}
// Breaking it down:
// let i = 1 β runs once before the loop starts
// i <= 5 β checked before each iteration
// i++ β runs after each iteration
// Count by 2s:
// for (let i = 0; i < 10; i += 2) { ... }
// Count backwards:
// for (let i = 10; i >= 1; i--) { ... }
// C#: same three-part syntax as JavaScript
for (int i = 1; i <= 5; i++)
{
Console.WriteLine(i);
}
// The pattern is identical to JavaScript:
// for (initialize; condition; update)
// Count by 2s:
// for (int i = 0; i < 10; i += 2) { ... }
// Count backwards:
// for (int i = 10; i >= 1; i--) { ... }
Syntax Comparison
| Task | π Python | β‘ JavaScript / π· C# |
|---|---|---|
| 0 to 4 | for i in range(5) |
for (let i = 0; i < 5; i++) |
| 1 to 10 | for i in range(1, 11) |
for (let i = 1; i <= 10; i++) |
| Even numbers 0β8 | for i in range(0, 10, 2) |
for (let i = 0; i < 10; i += 2) |
| Countdown 5 to 1 | for i in range(5, 0, -1) |
for (let i = 5; i >= 1; i--) |
β οΈ Python's range() Is Exclusive at the End
range(1, 5) gives you 1, 2, 3, 4 β not 5. The stop value is excluded. This is the most common beginner mistake with range(). If you want 1 through 5, use range(1, 6).
π Instructor Note: Delivery Guidance
Students coming from math will expect "1 to 5" to include 5. Spend a moment explaining why Python's exclusive-end convention exists (it makes range(len(list)) work cleanly and avoids off-by-one errors in many cases). For the JS/C# side, emphasize reading the three-part for loop like a sentence: "start at 1, keep going while β€ 5, add 1 each time." Have students trace through a loop with pen and paper for their first few examples.
Looping Over Collections
Often you don't want to count β you want to do something with each item in a list. All three languages have a convenient way to do this.
# Python: for...in (same keyword, no range needed)
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"I like {fruit}!")
# Output:
# I like apple!
# I like banana!
# I like cherry!
# Need the index too? Use enumerate():
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
// JavaScript: for...of (not for...in!)
let fruits = ["apple", "banana", "cherry"];
for (let fruit of fruits) {
console.log(`I like ${fruit}!`);
}
// Need the index too? Use forEach() or entries():
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
// β οΈ WARNING: for...in loops over KEYS (indices), not values
// for (let i in fruits) β "0", "1", "2" (strings, not items)
// Always use for...of for arrays!
// C#: foreach (dedicated keyword)
string[] fruits = { "apple", "banana", "cherry" };
foreach (string fruit in fruits)
{
Console.WriteLine($"I like {fruit}!");
}
// Need the index too? Use a regular for loop:
for (int i = 0; i < fruits.Length; i++)
{
Console.WriteLine($"{i}: {fruits[i]}");
}
// Or use LINQ (more advanced):
// foreach (var (fruit, index) in fruits.Select((f, i) => (f, i)))
// {
// Console.WriteLine($"{index}: {fruit}");
// }
π‘ Pattern Recognition: JS/C# Share a Family
Notice the trend from the conditionals lesson continuing here: JavaScript and C# share syntax DNA (the three-part for loop, curly braces, semicolons). Python takes its own path with for...in range() and for...in collection. In Python, both counting and iterating use the same for x in structure β the only difference is what comes after in.
while Loops
A while loop keeps running as long as a condition is true. You use it when you don't know in advance how many iterations you need.
# Python: while + condition + colon
count = 0
while count < 5:
print(count)
count += 1 # Don't forget this! (infinite loop otherwise)
# Output: 0, 1, 2, 3, 4
// JavaScript: while + parentheses + braces
let count = 0;
while (count < 5) {
console.log(count);
count++; // Don't forget this!
}
// Output: 0, 1, 2, 3, 4
// C#: same structure as JavaScript
int count = 0;
while (count < 5)
{
Console.WriteLine(count);
count++; // Don't forget this!
}
// Output: 0, 1, 2, 3, 4
β οΈ The Infinite Loop Trap
If your condition never becomes false, the loop runs forever and your program hangs. The most common cause: forgetting to update the variable that the condition checks. Always make sure something inside the loop moves you closer to the exit condition.
# INFINITE LOOP β Don't do this!
# count = 0
# while count < 5:
# print(count)
# # Oops β count never changes, so count < 5 is always True
A Real Use Case: Input Validation
while loops shine when you're waiting for valid user input β you can't know in advance how many tries it will take.
# Keep asking until the user enters a valid number
while True:
user_input = input("Enter a number between 1 and 10: ")
if user_input.isdigit():
number = int(user_input)
if 1 <= number <= 10:
break # Valid! Exit the loop
print("Invalid input. Try again.")
print(f"You entered: {number}")
// Browser: prompt returns a string (or null)
let number;
while (true) {
let userInput = prompt("Enter a number between 1 and 10:");
number = parseInt(userInput);
if (!isNaN(number) && number >= 1 && number <= 10) {
break; // Valid! Exit the loop
}
console.log("Invalid input. Try again.");
}
console.log(`You entered: ${number}`);
int number;
while (true)
{
Console.Write("Enter a number between 1 and 10: ");
string userInput = Console.ReadLine();
if (int.TryParse(userInput, out number) && number >= 1 && number <= 10)
{
break; // Valid! Exit the loop
}
Console.WriteLine("Invalid input. Try again.");
}
Console.WriteLine($"You entered: {number}");
break and continue
These two keywords give you fine-grained control over loop execution:
breakβ immediately exit the loop entirelycontinueβ skip the rest of this iteration and jump to the next one
loop body"] F --> A B -->|False| E style C fill:#f59e0b,stroke:#d97706,color:#fff,stroke-width:2px style D fill:#ef4444,stroke:#dc2626,color:#fff,stroke-width:2px
# Find the first negative number in a list
numbers = [4, 7, 2, -3, 8, 1]
for num in numbers:
if num < 0:
print(f"Found negative number: {num}")
break # Stop searching β we found one
print(f"Checked {num} β positive")
# Output:
# Checked 4 β positive
# Checked 7 β positive
# Checked 2 β positive
# Found negative number: -3
let numbers = [4, 7, 2, -3, 8, 1];
for (let num of numbers) {
if (num < 0) {
console.log(`Found negative number: ${num}`);
break;
}
console.log(`Checked ${num} β positive`);
}
int[] numbers = { 4, 7, 2, -3, 8, 1 };
foreach (int num in numbers)
{
if (num < 0)
{
Console.WriteLine($"Found negative number: {num}");
break;
}
Console.WriteLine($"Checked {num} β positive");
}
# Print only odd numbers from 1 to 10
for i in range(1, 11):
if i % 2 == 0:
continue # Skip even numbers
print(i)
# Output: 1, 3, 5, 7, 9
// Print only odd numbers from 1 to 10
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
continue; // Skip even numbers
}
console.log(i);
}
// Print only odd numbers from 1 to 10
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue; // Skip even numbers
}
Console.WriteLine(i);
}
π‘ Good News: break and continue Are the Same Everywhere
Unlike many features we've compared, break and continue work identically across Python, JavaScript, and C#. Same keywords, same behavior. One less thing to worry about when switching languages.
Nested Loops
You can put a loop inside another loop. The inner loop runs completely for each iteration of the outer loop. This is useful for grids, tables, and combinations.
# Print a 3Γ3 coordinate grid
for row in range(3):
for col in range(3):
print(f"({row},{col})", end=" ")
print() # New line after each row
# Output:
# (0,0) (0,1) (0,2)
# (1,0) (1,1) (1,2)
# (2,0) (2,1) (2,2)
// Print a 3Γ3 coordinate grid
for (let row = 0; row < 3; row++) {
let line = "";
for (let col = 0; col < 3; col++) {
line += `(${row},${col}) `;
}
console.log(line.trim());
}
// Print a 3Γ3 coordinate grid
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 3; col++)
{
Console.Write($"({row},{col}) ");
}
Console.WriteLine(); // New line after each row
}
β οΈ Nested Loop Performance
A loop inside a loop multiplies the iteration count. A 10Γ10 nested loop runs 100 times. A 1000Γ1000 nested loop runs one million times. For beginners this rarely matters, but it's good to be aware that nested loops can get slow with large data. We'll revisit this when we talk about algorithms in later courses.
π Instructor Note: Delivery Guidance
Nested loops are one of the first "hard" concepts for beginners. Use the grid/coordinate example first because it's visual and easy to trace. Then show the multiplication table exercise as a practical application. Encourage students to trace through nested loops with a table: "outer = 0, inner goes 0,1,2; outer = 1, inner goes 0,1,2; ..." β this manual tracing builds understanding much faster than just reading the code.
for vs. while β When to Use Which
Use for when⦠|
Use while when⦠|
|---|---|
| You know exactly how many iterations | You don't know how many iterations |
| You're iterating over a collection | You're waiting for a condition to change |
| Counting from A to B | Reading user input until it's valid |
| Processing each item in a list | Running a game loop |
| "Do this 10 times" | "Keep going until the user says stop" |
β Rule of Thumb
If you can express the problem as "for each item" or "do this N times," use a for loop. If you can express it as "keep going untilβ¦," use a while loop. When in doubt, for is usually the safer choice because it's harder to accidentally create an infinite loop.
Exercises
ποΈ Exercise 1: Multiplication Table
Objective: Print a multiplication table for a given number (1 through 10).
Example output for number = 7:
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
...
7 x 10 = 70
β Solution
number = 7
print(f"Multiplication table for {number}:")
print("-" * 20)
for i in range(1, 11):
result = number * i
print(f"{number} x {i:2d} = {result:3d}")
let number = 7;
console.log(`Multiplication table for ${number}:`);
console.log("-".repeat(20));
for (let i = 1; i <= 10; i++) {
let result = number * i;
console.log(`${number} x ${String(i).padStart(2)} = ${String(result).padStart(3)}`);
}
int number = 7;
Console.WriteLine($"Multiplication table for {number}:");
Console.WriteLine(new string('-', 20));
for (int i = 1; i <= 10; i++)
{
int result = number * i;
Console.WriteLine($"{number} x {i,2} = {result,3}");
}
ποΈ Exercise 2: FizzBuzz
Objective: The classic programming challenge! Print numbers 1 to 30, but:
- For multiples of 3, print "Fizz" instead of the number
- For multiples of 5, print "Buzz" instead of the number
- For multiples of both 3 and 5, print "FizzBuzz"
Hint: Check the "both" case first β why?
β Solution
for i in range(1, 31):
if i % 3 == 0 and i % 5 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
# Why check "both" first? Because 15 is divisible by 3 AND 5.
# If we checked "divisible by 3" first, it would print "Fizz"
# and never reach the "both" check.
for (let i = 1; i <= 30; i++) {
if (i % 3 === 0 && i % 5 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
for (int i = 1; i <= 30; i++)
{
if (i % 3 == 0 && i % 5 == 0)
Console.WriteLine("FizzBuzz");
else if (i % 3 == 0)
Console.WriteLine("Fizz");
else if (i % 5 == 0)
Console.WriteLine("Buzz");
else
Console.WriteLine(i);
}
ποΈ Exercise 3: Number Guessing Game
Objective: Create a number guessing game using a while loop.
- Set a secret number (hardcode it for now)
- Loop: ask the user to guess
- Tell them "Too high!" or "Too low!"
- When they guess correctly, print how many attempts it took
β Solution
secret = 42
attempts = 0
print("I'm thinking of a number between 1 and 100!")
while True:
guess_input = input("Your guess: ")
if not guess_input.isdigit():
print("Please enter a valid number.")
continue
guess = int(guess_input)
attempts += 1
if guess < secret:
print("Too low!")
elif guess > secret:
print("Too high!")
else:
print(f"π Correct! You got it in {attempts} attempts!")
break
let secret = 42;
let attempts = 0;
console.log("I'm thinking of a number between 1 and 100!");
while (true) {
let guessInput = prompt("Your guess:");
let guess = parseInt(guessInput);
if (isNaN(guess)) {
console.log("Please enter a valid number.");
continue;
}
attempts++;
if (guess < secret) {
console.log("Too low!");
} else if (guess > secret) {
console.log("Too high!");
} else {
console.log(`π Correct! You got it in ${attempts} attempts!`);
break;
}
}
int secret = 42;
int attempts = 0;
Console.WriteLine("I'm thinking of a number between 1 and 100!");
while (true)
{
Console.Write("Your guess: ");
string guessInput = Console.ReadLine();
if (!int.TryParse(guessInput, out int guess))
{
Console.WriteLine("Please enter a valid number.");
continue;
}
attempts++;
if (guess < secret)
Console.WriteLine("Too low!");
else if (guess > secret)
Console.WriteLine("Too high!");
else
{
Console.WriteLine($"π Correct! You got it in {attempts} attempts!");
break;
}
}
π Instructor Note: Delivery Guidance
Exercise 1 (multiplication table) is the warm-up β it reinforces counting for loops. Exercise 2 (FizzBuzz) is a programming classic and makes a great class activity; walk through the first few numbers as a group and ask students why order matters in the if/elif chain. Exercise 3 (guessing game) is the star β it naturally demonstrates while True with break, uses continue for input validation, and is fun to play. If students finish early, challenge them to add a random number (import random in Python, Math.random() in JS, Random class in C#) instead of hardcoding the secret.
Summary
π Key Takeaways
forloops are for counting (range()in Python, three-part syntax in JS/C#) and iterating over collections- Python uses
for x in range()andfor x in collectionβ one syntax for both counting and iterating - JavaScript and C# share the classic
for (init; cond; step)pattern and havefor...of/foreachfor collections whileloops repeat as long as a condition is true β perfect when you don't know the iteration countbreakexits a loop immediately;continueskips to the next iteration- Always make sure
whileloops have an exit condition to avoid infinite loops - Use
forwhen you know the count or have a collection; usewhilewhen waiting for a condition
π What's Next?
You can now make decisions and repeat actions. In the next lesson, we'll add one more tool to your control flow toolkit: logical operators and truthiness β how to combine conditions and understand what each language considers "truthy" or "falsy."
π― Quick Check
Question 1: What does range(2, 8) produce in Python?
Question 2: What's the difference between break and continue?