6. Loops¶
What & why¶
Loops repeat work: process every item in a list, retry until input is valid, count from 1 to 100. In Swift you'll mostly use for-in over a sequence; while and repeat-while handle the "until something happens" cases.
for-in over a range¶
Ranges:
1...5— closed: 1, 2, 3, 4, 50..<5— half-open: 0, 1, 2, 3, 4 (the upper bound is excluded; ideal for indices)5...and..<5— one-sided (used for slicing andswitch, not for looping forever/backwards)
If you don't need the counter, use _:
for-in over collections¶
let scores = [90, 72, 85]
for s in scores {
print(s)
}
for ch in "hey" {
print(ch)
}
let ages = ["Ada": 36, "Linus": 54]
for (name, age) in ages { // order is not guaranteed
print("\(name) is \(age)")
}
The loop constant is immutable — you can't assign to s. To modify elements in place, loop over indices:
Index and element: enumerated()¶
let fruits = ["apple", "banana", "cherry"]
for (index, fruit) in fruits.enumerated() {
print("\(index + 1). \(fruit)")
}
Counting backwards and by steps¶
for i in (1...5).reversed() { print(i) } // 5 4 3 2 1
for i in stride(from: 0, to: 10, by: 3) { print(i) } // 0 3 6 9 (excludes 10)
for i in stride(from: 10, through: 0, by: -5) { print(i) } // 10 5 0 (includes 0)
while¶
Repeat while a condition holds — when you don't know the count in advance:
var n = 27
var steps = 0
while n != 1 {
n = n.isMultiple(of: 2) ? n / 2 : 3 * n + 1
steps += 1
}
print("Collatz steps: \(steps)")
repeat-while¶
Like while, but the body runs at least once. Perfect for input validation:
var age: Int?
repeat {
print("Enter age (1-120): ", terminator: "")
age = Int(readLine() ?? "")
} while age == nil || !(1...120).contains(age!)
print("Age: \(age!)")
(The ?? "" and ! bits are covered in Optionals. Here, age! is safe because the loop only ends once age is non-nil.)
break, continue, and labels¶
for i in 1...10 {
if i.isMultiple(of: 2) { continue } // skip the rest of this iteration
if i > 7 { break } // leave the loop entirely
print(i, terminator: " ")
}
// 1 3 5 7
break and continue affect the innermost loop. To control an outer one, give it a label:
outer: for row in 1...3 {
for col in 1...3 {
if row * col == 4 { break outer } // leaves both loops
print(row * col, terminator: " ")
}
}
Reading input until it runs out¶
var total = 0
while let line = readLine() { // returns nil at end of input
if let value = Int(line) {
total += value
}
}
print("sum: \(total)")
Try it with printf '1\n2\n3\n' | swift run, or type numbers and finish with Ctrl+D (Ctrl+Z then Enter on Windows).
where filters¶
Nested loops¶
Functional alternatives (a preview)¶
Often a loop that builds a new collection is clearer as map / filter / reduce:
let squares = (1...5).map { $0 * $0 } // [1, 4, 9, 16, 25]
let evens = (1...10).filter { $0.isMultiple(of: 2) } // [2, 4, 6, 8, 10]
let sum = (1...100).reduce(0, +) // 5050
You'll learn closures properly in Intermediate. Use whichever reads best.
Common mistakes¶
- Using
1...nwhennmight be0:1...0crashes ("Range requires lowerBound <= upperBound"). Use0..<n, orstride. - Trying to modify the loop variable: it's a constant.
- Modifying a collection while iterating over it — the loop iterates over a copy, so changes won't affect it, which may not be what you expected.
- Infinite
whileloops from forgetting to update the condition. - Off-by-one with
...vs..<. Prefer..<witharray.count, or better, iterate the array directly. - Reversed ranges:
for i in 10...1crashes. Use(1...10).reversed()orstride.
Exercises¶
- Print 1–100, but print "Fizz" for multiples of 3, "Buzz" for multiples of 5, and "FizzBuzz" for both.
- Read integers until end-of-input and print the count, sum, minimum, maximum, and average. Skip lines that aren't numbers.
- Number guessing game: pick
Int.random(in: 1...100), let the user guess with "higher"/"lower" hints, and count the guesses. Handle non-numeric input. - Print a right triangle of
*of height N using nested loops. - Print all primes below 100.
- Print a multiplication table (1–10) with aligned columns.
- Use a labeled
breakto find the first pair(a, b)with1 <= a, b <= 20anda * b == 91.
Recap¶
for-inover ranges (1...5,0..<n), collections, strings, and dictionaries.enumerated()for index + element;stridefor custom steps;.reversed()to count down.whilefor unknown counts;repeat-whileruns at least once.break/continueact on the innermost loop; labels reach outer loops.while let line = readLine()reads until input ends.
Next: Arrays →