← Back to Learning Hub

Lesson 6: Loops & Algorithm Foundations

Mastering iteration and thinking like a programmer

90 minutes Loops Algorithms

Today's Goal

You've used while loops in your game loops, but there's a whole world of iteration patterns to explore. Today we'll master loops and use them to understand how algorithms work.

By the end of this lesson, you'll be able to write any kind of loop confidently and implement your first real algorithm.

Why this matters: Almost every program uses loops. Searching, sorting, processing data, game logic - it all depends on iteration. Understanding loops deeply is the foundation of algorithmic thinking.

Part 1: The Two Loop Types 10 min

While vs For: When to Use Each

Python has two main loop types. Each has its purpose:

Loop Type Use When... Example Scenario
while You don't know how many times to loop Game loop until player quits, input validation
for You know what you're iterating over Process each item in a list, repeat N times
While Loop - Unknown iterations
# Keep asking until valid input
password = ""
while password != "secret123":
    password = input("Enter password: ")
print("Access granted!")

# Game loop - runs until player decides to stop
playing = True
while playing:
    action = input("What do you do? ")
    if action == "quit":
        playing = False
For Loop - Known iterations
# Process each pet in a list
pets = ["Max", "Luna", "Buddy"]
for pet in pets:
    print(f"Feeding {pet}...")

# Repeat exactly 5 times
for i in range(5):
    print(f"Attempt {i + 1}")

# Go through each character in a string
word = "Python"
for letter in word:
    print(letter)

Quick Rule

For loop: "Do this for each item in this collection"

While loop: "Keep doing this while this condition is true"

Quick Check

Which loop type would you use for:

  • Displaying all items in a shop inventory?
  • Asking user for input until they enter a valid number?
  • Feeding each pet in a PetShop?
Answers
  • Shop inventory: for - you know the items
  • Valid input: while - unknown attempts needed
  • Feed pets: for - iterate over pet list

Part 2: For Loop Deep Dive 20 min

Iterating Over Different Types

The for loop can iterate over any "iterable" - lists, strings, dictionaries, and more.

Iterating Over Lists
pets = ["Max", "Luna", "Buddy"]

# Basic iteration
for pet in pets:
    print(pet)

# With index using enumerate()
for index, pet in enumerate(pets):
    print(f"{index}: {pet}")
# Output:
# 0: Max
# 1: Luna
# 2: Buddy

# Starting enumerate at 1 (useful for display)
for position, pet in enumerate(pets, start=1):
    print(f"Pet #{position}: {pet}")
# Output:
# Pet #1: Max
# Pet #2: Luna
# Pet #3: Buddy
Iterating Over Strings
word = "PYTHON"

# Each character
for char in word:
    print(char)

# Count vowels in a word
vowels = "aeiouAEIOU"
count = 0
for char in word:
    if char in vowels:
        count += 1
print(f"Vowels found: {count}")  # Output: 1
Iterating Over Dictionaries
shop_items = {
    'apple': 1.50,
    'bread': 2.00,
    'milk': 3.50
}

# Keys only (default)
for item in shop_items:
    print(item)  # apple, bread, milk

# Values only
for price in shop_items.values():
    print(price)  # 1.5, 2.0, 3.5

# Both keys and values
for item, price in shop_items.items():
    print(f"{item}: ${price:.2f}")
# Output:
# apple: $1.50
# bread: $2.00
# milk: $3.50

The range() Function

range() generates a sequence of numbers. Essential for controlled iteration.

range() Patterns
# range(stop) - 0 to stop-1
for i in range(5):
    print(i)  # 0, 1, 2, 3, 4

# range(start, stop) - start to stop-1
for i in range(1, 6):
    print(i)  # 1, 2, 3, 4, 5

# range(start, stop, step) - with custom step
for i in range(0, 10, 2):
    print(i)  # 0, 2, 4, 6, 8

# Counting backwards
for i in range(5, 0, -1):
    print(i)  # 5, 4, 3, 2, 1
print("Liftoff!")

Common Mistake

range(5) gives you 0, 1, 2, 3, 4 - NOT 1, 2, 3, 4, 5!

If you want 1-5, use range(1, 6)

Practice

What would these print?

  • for i in range(3): print(i)
  • for i in range(2, 5): print(i)
  • for i in range(10, 0, -2): print(i)
Answers
  • range(3): 0, 1, 2
  • range(2, 5): 2, 3, 4
  • range(10, 0, -2): 10, 8, 6, 4, 2

Part 3: Loop Control Statements 15 min

Controlling Loop Flow

Sometimes you need to exit a loop early or skip certain iterations. Python gives you three tools:

Statement What It Does
break Exit the loop immediately
continue Skip to the next iteration
else Runs if loop completes without break
break - Exit Early
# Find the first pet named "Luna"
pets = ["Max", "Luna", "Buddy", "Luna"]

for pet in pets:
    if pet == "Luna":
        print(f"Found {pet}!")
        break  # Stop searching, we found it
    print(f"Checking {pet}...")

# Output:
# Checking Max...
# Found Luna!

# Without break, it would keep going and find both Lunas
continue - Skip This One
# Feed all pets except the cat (she's picky)
pets = [
    {"name": "Max", "species": "dog"},
    {"name": "Whiskers", "species": "cat"},
    {"name": "Buddy", "species": "dog"}
]

for pet in pets:
    if pet["species"] == "cat":
        print(f"Skipping {pet['name']} (cats feed themselves)")
        continue  # Skip to next pet

    print(f"Feeding {pet['name']}...")

# Output:
# Feeding Max...
# Skipping Whiskers (cats feed themselves)
# Feeding Buddy...
else on Loops - Python's Secret Feature
# Search for an item - else runs if NOT found
shopping_list = ["apple", "bread", "milk"]
search_item = "eggs"

for item in shopping_list:
    if item == search_item:
        print(f"Found {search_item}!")
        break
else:
    # This runs ONLY if we didn't break
    print(f"{search_item} not in list!")

# Output: eggs not in list!

# Now search for "bread"
search_item = "bread"
for item in shopping_list:
    if item == search_item:
        print(f"Found {search_item}!")
        break
else:
    print(f"{search_item} not in list!")

# Output: Found bread!

The else clause on loops is unique to Python. Think of it as "no break" - it runs when the loop completes normally without hitting a break.

Think About It

In the Pet Simulator, where might you use:

  • break - to exit a loop early?
  • continue - to skip certain items?
Ideas
  • break: Exit the game loop when user types "quit"
  • break: Stop searching for a pet once found
  • continue: Skip feeding pets that aren't hungry
  • continue: Skip sleeping pets when displaying status

Part 4: Common Loop Patterns 15 min

Patterns You'll Use Again and Again

These patterns appear everywhere in programming. Master them and you can solve most problems.

Pattern 1: Counting
# Count how many pets are hungry
pets = [
    {"name": "Max", "hunger": 80},
    {"name": "Luna", "hunger": 30},
    {"name": "Buddy", "hunger": 75}
]

hungry_count = 0
for pet in pets:
    if pet["hunger"] > 50:
        hungry_count += 1

print(f"{hungry_count} pets are hungry")  # 2 pets are hungry
Pattern 2: Accumulation (Summing)
# Calculate total price of cart
cart = [
    {"item": "apple", "price": 1.50},
    {"item": "bread", "price": 2.00},
    {"item": "milk", "price": 3.50}
]

total = 0
for item in cart:
    total += item["price"]

print(f"Total: ${total:.2f}")  # Total: $7.00

# Python shortcut: sum() with generator
total = sum(item["price"] for item in cart)
Pattern 3: Finding (First Match)
# Find the first hungry pet
pets = [
    {"name": "Max", "hunger": 30},
    {"name": "Luna", "hunger": 80},
    {"name": "Buddy", "hunger": 75}
]

hungry_pet = None
for pet in pets:
    if pet["hunger"] > 50:
        hungry_pet = pet
        break  # Found one, stop searching

if hungry_pet:
    print(f"Feed {hungry_pet['name']} first!")
else:
    print("No hungry pets!")
Pattern 4: Filtering (All Matches)
# Get ALL hungry pets
pets = [
    {"name": "Max", "hunger": 30},
    {"name": "Luna", "hunger": 80},
    {"name": "Buddy", "hunger": 75}
]

hungry_pets = []
for pet in pets:
    if pet["hunger"] > 50:
        hungry_pets.append(pet)

print(f"Hungry pets: {[p['name'] for p in hungry_pets]}")
# Hungry pets: ['Luna', 'Buddy']

# Python shortcut: list comprehension
hungry_pets = [pet for pet in pets if pet["hunger"] > 50]
Pattern 5: Transforming
# Get just the names from pet objects
pets = [
    {"name": "Max", "hunger": 30},
    {"name": "Luna", "hunger": 80},
    {"name": "Buddy", "hunger": 75}
]

pet_names = []
for pet in pets:
    pet_names.append(pet["name"])

print(pet_names)  # ['Max', 'Luna', 'Buddy']

# Python shortcut: list comprehension
pet_names = [pet["name"] for pet in pets]

Pattern Summary

  • Counting: Initialize counter, increment when condition met
  • Accumulation: Initialize total, add each value
  • Finding: Initialize to None, set and break when found
  • Filtering: Initialize empty list, append matches
  • Transforming: Initialize empty list, append transformed values

Part 5: Introduction to Algorithms 20 min

What is an Algorithm?

An algorithm is a step-by-step procedure to solve a problem. It's like a recipe - specific instructions that always produce the same result.

Real-World Algorithms:

  • Finding a word in a dictionary
  • Sorting playing cards in your hand
  • Finding the shortest route on a map
  • Searching for a contact in your phone

Key insight: Algorithms are everywhere in programming. When you write a loop to search for something, you're implementing an algorithm!

Linear Search Algorithm

The simplest search algorithm: check each item one by one until you find what you're looking for.

The Steps:

  1. Start at the first item
  2. Check if it's the item we want
  3. If yes, we're done - return it
  4. If no, move to the next item
  5. Repeat until found or no items left
Linear Search - Basic Implementation
def linear_search(items, target):
    """
    Search for target in items list.
    Returns the index if found, -1 if not found.
    """
    for index in range(len(items)):
        if items[index] == target:
            return index  # Found it!

    return -1  # Not found


# Test it
numbers = [4, 2, 7, 1, 9, 3]
result = linear_search(numbers, 7)
print(f"Found at index: {result}")  # Found at index: 2

result = linear_search(numbers, 5)
print(f"Found at index: {result}")  # Found at index: -1
Linear Search - Pythonic Version
def linear_search(items, target):
    """Search for target in items. Returns index or -1."""
    for index, item in enumerate(items):
        if item == target:
            return index
    return -1


# Even more Pythonic - using 'in' for existence check
def find_item(items, target):
    """Check if target exists and return it."""
    for item in items:
        if item == target:
            return item
    return None

Linear Search with Objects

In real programs, you often search through objects, not just simple values.

Searching a Pet List
def find_pet_by_name(pets, name):
    """Find a pet by name. Returns the pet or None."""
    for pet in pets:
        if pet["name"].lower() == name.lower():
            return pet
    return None


def find_hungry_pets(pets, hunger_threshold=50):
    """Find all pets above hunger threshold."""
    hungry = []
    for pet in pets:
        if pet["hunger"] > hunger_threshold:
            hungry.append(pet)
    return hungry


# Usage
pets = [
    {"name": "Max", "species": "dog", "hunger": 30},
    {"name": "Luna", "species": "cat", "hunger": 80},
    {"name": "Buddy", "species": "dog", "hunger": 75}
]

pet = find_pet_by_name(pets, "luna")
if pet:
    print(f"Found {pet['name']} the {pet['species']}")
else:
    print("Pet not found")

hungry = find_hungry_pets(pets)
print(f"Hungry pets: {[p['name'] for p in hungry]}")

Algorithm Efficiency: Why It Matters

How fast is linear search? It depends on where the item is:

Scenario Comparisons Needed Example (100 items)
Best case (first item) 1 1 comparison
Worst case (last or not found) N (all items) 100 comparisons
Average case N/2 50 comparisons

The Big Picture

Linear search works fine for small lists. But imagine searching through 1 million items - worst case means 1 million comparisons!

In future lessons, we'll learn Binary Search, which can search 1 million sorted items in just 20 comparisons.

Think About It

  • In your Pet Simulator, if you have 10 pets and search by name, what's the worst case number of comparisons?
  • Why do we return as soon as we find the item instead of checking all items?
Answers
  • Worst case: 10 comparisons (item is last or doesn't exist)
  • Why return early: No point checking more items once we've found what we want - it would waste time and is unnecessary work

Part 6: Putting It Together 10 min

Building a Search Feature for PetShop

Let's add search functionality to the PetShop class from your homework.

PetShop with Search Methods
class PetShop:
    """Manages multiple pets with search capabilities."""

    def __init__(self):
        self.pets = []

    def add_pet(self, pet):
        """Add a pet to the shop."""
        self.pets.append(pet)

    # --- SEARCH METHODS ---

    def find_by_name(self, name):
        """Linear search for a pet by name."""
        for pet in self.pets:
            if pet.name.lower() == name.lower():
                return pet
        return None

    def find_by_species(self, species):
        """Find ALL pets of a species."""
        matches = []
        for pet in self.pets:
            if pet.species.lower() == species.lower():
                matches.append(pet)
        return matches

    def find_hungry_pets(self, threshold=50):
        """Find all pets with hunger above threshold."""
        hungry = []
        for pet in self.pets:
            if pet.hunger > threshold:
                hungry.append(pet)
        return hungry

    def count_by_species(self):
        """Count how many of each species."""
        counts = {}
        for pet in self.pets:
            species = pet.species
            if species in counts:
                counts[species] += 1
            else:
                counts[species] = 1
        return counts

    # --- DISPLAY METHODS ---

    def show_all(self):
        """Display all pets."""
        if not self.pets:
            print("No pets in shop!")
            return

        print(f"\n--- Pet Shop ({len(self.pets)} pets) ---")
        for i, pet in enumerate(self.pets, start=1):
            print(f"{i}. {pet.name} ({pet.species})")


# Usage example
shop = PetShop()
shop.add_pet(Pet("Max", "dog"))
shop.add_pet(Pet("Luna", "cat"))
shop.add_pet(Pet("Buddy", "dog"))
shop.add_pet(Pet("Nemo", "fish"))

# Find a specific pet
pet = shop.find_by_name("luna")
if pet:
    pet.status()

# Find all dogs
dogs = shop.find_by_species("dog")
print(f"Dogs: {[p.name for p in dogs]}")  # ['Max', 'Buddy']

# Count species
print(shop.count_by_species())  # {'dog': 2, 'cat': 1, 'fish': 1}

What We Used

  • For loops to iterate over pets
  • Linear search with early return for find_by_name
  • Filtering pattern for find_by_species and find_hungry_pets
  • Counting pattern for count_by_species
  • enumerate() for numbered display

Part 7: Summary 5 min

Key Concepts

Loop Types

Type When to Use Syntax
for Known collection or count for item in collection:
while Unknown iterations while condition:

Loop Control

Statement Effect
break Exit loop immediately
continue Skip to next iteration
else Runs if no break occurred

Common Patterns

  • Counting: Count items matching a condition
  • Accumulation: Sum/combine values
  • Finding: Find first match and return early
  • Filtering: Collect all matches
  • Transforming: Convert items to new form

Linear Search Algorithm

  • Check each item one by one
  • Return when found, -1/None if not found
  • Efficiency: O(n) - worst case checks all items

Skills Unlocked

  • Use for loops with lists, strings, dicts, and range()
  • Control loops with break and continue
  • Apply common loop patterns to solve problems
  • Understand and implement linear search
  • Think about algorithm efficiency

Homework: Loop Mastery Challenges Download & Complete

Your Mission

Practice loops and algorithms with challenges that build on the Pet Simulator. This homework reinforces everything we covered today.

  • Loop patterns - counting, summing, searching, filtering
  • Algorithm implementation - linear search variations
  • Real problem solving - apply patterns to new problems

Download: homework_loops.py

Click here to download the homework file

What You'll Build:

Part 1: Loop Basics
  • Print patterns using range()
  • Iterate over different data types
  • Use enumerate() for indexed access
Part 2: Loop Patterns
  • Counting occurrences
  • Calculating totals
  • Finding minimum/maximum
Part 3: Search Algorithms
  • Implement linear search
  • Search with conditions
  • Return index vs return item
Part 4: PetShop Challenges
  • Add search methods to PetShop
  • Filter pets by criteria
  • Generate statistics
Part 5: Bonus - Mini Games (Optional)
  • Number guessing game with limited attempts
  • Word scramble unscrambler

Remember: Focus on understanding the patterns. Once you recognize them, you can apply them anywhere!

Next lesson: We'll explore more algorithms - sorting algorithms (how to arrange items in order) and binary search (searching sorted data much faster than linear search).

← Back to Blake's Learning Hub