Lua - Loops
Overview
Estimated time: 30–35 minutes
Loops allow you to repeat code blocks multiple times. Lua provides three types of loops: for loops (numeric and generic), while loops, and repeat-until loops. This tutorial covers all loop types with practical examples.
Learning Objectives
- Master numeric for loops for counting iterations
- Use generic for loops with pairs and ipairs
- Implement while loops for condition-based repetition
- Apply repeat-until loops for post-test conditions
- Understand loop control with break and continue patterns
Prerequisites
- Understanding of Lua operators and conditions
- Knowledge of tables and basic data types
Numeric For Loops
Numeric for loops iterate over a range of numbers:
Basic Syntax
-- for variable = start, stop, step do
-- -- loop body
-- end
-- Simple counting loop
for i = 1, 5 do
print("Iteration", i)
end
print("---")
-- Counting backwards
for i = 5, 1, -1 do
print("Countdown", i)
end
print("---")
-- Custom step size
for i = 0, 10, 2 do
print("Even number:", i)
end
Expected Output:
Iteration 1
Iteration 2
Iteration 3
Iteration 4
Iteration 5
---
Countdown 5
Countdown 4
Countdown 3
Countdown 2
Countdown 1
---
Even number: 0
Even number: 2
Even number: 4
Even number: 6
Even number: 8
Even number: 10
Practical Numeric For Loop Examples
-- Calculate factorial
local function factorial(n)
local result = 1
for i = 1, n do
result = result * i
end
return result
end
print("5! =", factorial(5))
-- Generate multiplication table
local function multiplication_table(num, max)
print("Multiplication table for", num)
for i = 1, max do
print(num .. " x " .. i .. " = " .. (num * i))
end
end
multiplication_table(7, 5)
-- Sum of numbers in range
local function sum_range(start, stop)
local total = 0
for i = start, stop do
total = total + i
end
return total
end
print("Sum of 1 to 10:", sum_range(1, 10))
Expected Output:
5! = 120
Multiplication table for 7
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
Sum of 1 to 10: 55
Generic For Loops
Generic for loops iterate over collections using iterator functions:
Using ipairs() for Arrays
local fruits = {"apple", "banana", "orange", "grape"}
-- ipairs() for array-like tables (consecutive integer keys)
print("Fruits list:")
for index, fruit in ipairs(fruits) do
print(index .. ".", fruit)
end
-- Processing array elements
local numbers = {10, 20, 30, 40, 50}
local sum = 0
for i, num in ipairs(numbers) do
sum = sum + num
print("Adding", num, "- Running total:", sum)
end
print("Final sum:", sum)
Expected Output:
Fruits list:
1. apple
2. banana
3. orange
4. grape
Adding 10 - Running total: 10
Adding 20 - Running total: 30
Adding 30 - Running total: 60
Adding 40 - Running total: 100
Adding 50 - Running total: 150
Final sum: 150
Using pairs() for All Table Elements
local student = {
name = "Alice",
age = 20,
grade = "A",
subjects = {"Math", "Physics", "Chemistry"}
}
-- pairs() for all key-value pairs
print("Student information:")
for key, value in pairs(student) do
if type(value) == "table" then
print(key .. ":", table.concat(value, ", "))
else
print(key .. ":", value)
end
end
-- Counting table elements
local inventory = {
sword = 1,
shield = 2,
potion = 5,
gold = 100
}
local item_count = 0
local total_value = 0
for item, quantity in pairs(inventory) do
item_count = item_count + 1
if item == "gold" then
total_value = total_value + quantity
else
total_value = total_value + quantity * 10 -- Assume each item worth 10 gold
end
print("Item:", item, "Quantity:", quantity)
end
print("Total items:", item_count)
print("Total value:", total_value)
Expected Output:
Student information:
subjects: Math, Physics, Chemistry
name: Alice
age: 20
grade: A
Item: sword Quantity: 1
Item: shield Quantity: 2
Item: potion Quantity: 5
Item: gold Quantity: 100
Total items: 4
Total value: 180
While Loops
While loops continue as long as a condition is true:
Basic While Loop
-- Simple counting with while
local count = 1
while count <= 5 do
print("Count:", count)
count = count + 1
end
-- User input simulation (in practice, you'd use io.read())
local attempts = 0
local max_attempts = 3
local success = false
while attempts < max_attempts and not success do
attempts = attempts + 1
print("Attempt", attempts)
-- Simulate random success (normally this would be user input)
if attempts == 2 then -- Simulate success on second attempt
success = true
print("Success!")
else
print("Failed, trying again...")
end
end
if not success then
print("Max attempts reached")
end
Expected Output:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Attempt 1
Failed, trying again...
Attempt 2
Success!
Practical While Loop Examples
-- Number guessing game logic
local function guess_number_game()
local secret = 42 -- In real game, this would be random
local guess = 0
local attempts = 0
print("Guess the number between 1 and 100!")
while guess ~= secret and attempts < 5 do
attempts = attempts + 1
-- Simulate user guesses
local guesses = {25, 60, 40, 42}
guess = guesses[attempts] or 0
print("Attempt " .. attempts .. ": Guessing " .. guess)
if guess < secret then
print("Too low!")
elseif guess > secret then
print("Too high!")
else
print("Correct! You won in " .. attempts .. " attempts!")
end
end
if guess ~= secret then
print("Game over! The number was " .. secret)
end
end
guess_number_game()
-- Processing until condition is met
local function process_queue()
local queue = {1, 2, 3, 4, 5}
local processed = 0
while #queue > 0 do
local item = table.remove(queue, 1) -- Remove first item
processed = processed + 1
print("Processing item " .. item .. " (Queue size: " .. #queue .. ")")
-- Stop if we've processed 3 items
if processed >= 3 then
print("Processed enough items, stopping")
break
end
end
print("Remaining in queue:", #queue)
end
process_queue()
Expected Output:
Guess the number between 1 and 100!
Attempt 1: Guessing 25
Too low!
Attempt 2: Guessing 60
Too high!
Attempt 3: Guessing 40
Too low!
Attempt 4: Guessing 42
Correct! You won in 4 attempts!
Processing item 1 (Queue size: 4)
Processing item 2 (Queue size: 3)
Processing item 3 (Queue size: 2)
Processed enough items, stopping
Remaining in queue: 2
Repeat-Until Loops
Repeat-until loops execute at least once and continue until a condition becomes true:
-- Basic repeat-until
local x = 1
repeat
print("x =", x)
x = x + 1
until x > 3
print("---")
-- Menu system example
local function show_menu()
local choice
local valid_choices = {1, 2, 3, 4}
repeat
print("\n=== Menu ===")
print("1. View Profile")
print("2. Settings")
print("3. Help")
print("4. Exit")
-- Simulate user choice (in real program, use io.read())
choice = math.random(1, 5) -- Sometimes invalid choice
print("User chose:", choice)
if choice == 1 then
print("Showing profile...")
elseif choice == 2 then
print("Opening settings...")
elseif choice == 3 then
print("Displaying help...")
elseif choice == 4 then
print("Goodbye!")
else
print("Invalid choice, please try again")
choice = nil -- Force loop to continue
end
until choice == 4 -- Continue until user chooses exit
end
-- Simulate one iteration of the menu
math.randomseed(42) -- For consistent output
local choice
repeat
choice = math.random(1, 5)
print("Simulated choice:", choice)
if choice == 4 then
print("Exit chosen")
elseif choice > 4 then
print("Invalid choice")
else
print("Valid menu choice")
end
until choice == 4 or choice <= 3 -- Exit on valid choice or exit
Expected Output:
x = 1
x = 2
x = 3
---
Simulated choice: 2
Valid menu choice
Nested Loops
Loops can be nested inside other loops:
-- Multiplication table (nested for loops)
print("Multiplication Table (1-5):")
print(" ", end="")
for j = 1, 5 do
io.write(string.format("%4d", j))
end
print()
for i = 1, 5 do
io.write(string.format("%3d:", i))
for j = 1, 5 do
io.write(string.format("%4d", i * j))
end
print()
end
-- Matrix operations
local function create_matrix(rows, cols, value)
local matrix = {}
for i = 1, rows do
matrix[i] = {}
for j = 1, cols do
matrix[i][j] = value or 0
end
end
return matrix
end
local function print_matrix(matrix)
for i = 1, #matrix do
local row = ""
for j = 1, #matrix[i] do
row = row .. string.format("%3d ", matrix[i][j])
end
print(row)
end
end
-- Create and display a 3x3 matrix
local matrix = create_matrix(3, 3, 0)
-- Fill matrix with values
for i = 1, 3 do
for j = 1, 3 do
matrix[i][j] = i + j
end
end
print("\n3x3 Matrix:")
print_matrix(matrix)
Expected Output:
Multiplication Table (1-5):
1 2 3 4 5
1: 1 2 3 4 5
2: 2 4 6 8 10
3: 3 6 9 12 15
4: 4 8 12 16 20
5: 5 10 15 20 25
3x3 Matrix:
2 3 4
3 4 5
4 5 6
Loop Control
Use break
to exit loops early:
-- Finding first element that meets condition
local numbers = {3, 7, 2, 9, 1, 8, 5}
local target = 9
print("Looking for", target)
for i, num in ipairs(numbers) do
print("Checking position " .. i .. ": " .. num)
if num == target then
print("Found " .. target .. " at position " .. i)
break -- Exit the loop early
end
end
-- Early exit from while loop
local function find_first_prime()
local number = 2
while true do -- Infinite loop
local is_prime = true
-- Check if number is prime
for i = 2, math.sqrt(number) do
if number % i == 0 then
is_prime = false
break -- Exit inner loop
end
end
if is_prime then
print("First prime found:", number)
break -- Exit outer loop
end
number = number + 1
end
end
find_first_prime()
-- Continue pattern (Lua doesn't have continue, but we can simulate it)
print("Even numbers from 1 to 10:")
for i = 1, 10 do
if i % 2 ~= 0 then
-- Skip odd numbers (simulate continue)
goto continue
end
print("Even number:", i)
::continue:: -- Label for goto
end
Expected Output:
Looking for 9
Checking position 1: 3
Checking position 2: 7
Checking position 3: 2
Checking position 4: 9
Found 9 at position 4
First prime found: 2
Even numbers from 1 to 10:
Even number: 2
Even number: 4
Even number: 6
Even number: 8
Even number: 10
Advanced Loop Patterns
Iterator Pattern
-- Custom iterator for even numbers
local function even_numbers(max)
local i = 0
return function()
i = i + 2
if i <= max then
return i
end
end
end
print("Even numbers up to 10:")
for num in even_numbers(10) do
print(num)
end
-- Iterator for file-like data
local function lines_iterator(text)
local lines = {}
for line in string.gmatch(text, "([^\n]+)") do
table.insert(lines, line)
end
local i = 0
return function()
i = i + 1
return lines[i]
end
end
local sample_text = "Line 1\nLine 2\nLine 3"
print("Processing lines:")
for line in lines_iterator(sample_text) do
print("Processing:", line)
end
Common Pitfalls
- Infinite loops: Ensure loop conditions will eventually become false
- Off-by-one errors: Check your loop bounds carefully
- Modifying tables during iteration: Can cause unexpected behavior
- Using wrong iterator: Use
ipairs()
for arrays,pairs()
for all table elements - Forgetting
do
: All loop statements requiredo
Checks for Understanding
- What are the three types of loops in Lua?
- What's the difference between
pairs()
andipairs()
? - How do you create a numeric for loop that counts backwards?
- What's the difference between while and repeat-until loops?
- How do you exit a loop early?
Show answers
- Numeric for loops, generic for loops, while loops, and repeat-until loops (4 types total)
ipairs()
iterates over consecutive integer keys starting from 1;pairs()
iterates over all key-value pairs- Use a negative step:
for i = 10, 1, -1 do
- While loops test the condition before each iteration; repeat-until loops test after, so they always execute at least once
- Use the
break
statement
Next Steps
Now that you can repeat code with loops, you're ready to learn about functions, which allow you to organize and reuse code blocks effectively.