Step 1 of 5 · Reading · ~3 min
Learn
Control Flow
Loops
Swift's workhorse loop is for ... in. It does not count — it walks a sequence, and a range is
just one kind of sequence.
for i in 1...3 {
print(i)
}
//> 1
//> 2
//> 3
Two range operators, one off-by-one
| Operator | Name | 1 ... 5 / 1 ..< 5 produces |
|---|---|---|
... | closed range | 1 2 3 4 5 |
..< | half-open range | 1 2 3 4 |
print(Array(1...5))
print(Array(1..<5))
print((1...5).count, (1..<5).count)
//> [1, 2, 3, 4, 5]
//> [1, 2, 3, 4]
//> 5 4
Use ..< when the upper bound is a count (for i in 0..<items.count) and ... when it is a
value you want included (for i in 1...n). Picking the wrong one is the most common loop bug
in any language, and Swift at least makes the choice visible in the syntax.
Walking things other than numbers
let names = ["ada", "grace", "alan"]
for name in names {
print(name)
}
for (i, name) in names.enumerated() {
print("\(i): \(name)")
}
//> ada
//> grace
//> alan
//> 0: ada
//> 1: grace
//> 2: alan
enumerated() is how you get an index without counting by hand. Reach for it instead of
for i in 0..<names.count — you can never index out of bounds with it.
Strings iterate by Character, and stride covers the "every nth" case:
for c in "hi!" {
print(c)
}
print(Array(stride(from: 0, to: 10, by: 3)))
//> h
//> i
//> !
//> [0, 3, 6, 9]
Filtering inside the loop header
A where clause skips iterations without an extra level of indentation:
var total = 0
for i in 1...5 where i % 2 == 1 {
total += i
}
print(total)
//> 9
while and repeat-while
Use while when you do not know how many iterations there will be:
var n = 16
var halvings = 0
while n > 1 {
n /= 2
halvings += 1
}
print(halvings)
//> 4
repeat ... while is Swift's name for do ... while — the body runs before the condition is
ever tested, so it always executes at least once:
var count = 3
repeat {
count -= 1
} while count > 0
print(count)
//> 0
Getting out early
break leaves the loop entirely; continue skips to the next iteration.
var kept: [Int] = []
for i in 1...10 {
if i % 2 == 0 { continue }
if i > 7 { break }
kept.append(i)
}
print(kept)
//> [1, 3, 5, 7]
continue fires on every even number, so i == 8 never reaches the break test — the loop ends
at 9 instead. Guard order matters inside loops just as it does inside a switch.
Your exercise
Read a positive integer n and print the sum 1 + 2 + ... + n.
The mistake the grader catches is the half-open range. Writing for i in 1..<n stops at
n - 1, so the first visible test with 5 prints 10 instead of 15, and the hidden test with
100 prints 4950 instead of 5050. You want 1...n. The other way to lose the test is to
print inside the loop — accumulate into a running total declared with var before the loop and
print once, after it.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…