Swift loops: the for-in loop
By Flavio Copes
Learn the for-in loop in Swift: iterate ranges, arrays, strings and dictionaries, get indexes with enumerated, filter with where, and use stride.
This tutorial belongs to the Swift series
The for-in loop is the loop you’ll use most in Swift. It iterates over a sequence: a range of numbers, an array, a string, a dictionary. You tell it what to loop over, and Swift hands you one element at a time.
The simplest case is a range. The closed range operator ... includes both ends:
for number in 1...5 {
print(number) // 1, 2, 3, 4, 5
}
The half-open range operator ..< excludes the last value:
for number in 1..<5 {
print(number) // 1, 2, 3, 4
}
Half-open ranges are handy with array indexes, since an array of 5 items has indexes 0 through 4.
Notice you don’t declare number with var or let. The loop creates the constant for you, fresh on each iteration.
Iterating over arrays
Give for-in an array and it walks through the elements in order:
let fruits = ["apple", "banana", "cherry"]
for fruit in fruits {
print(fruit)
}
What if you also need the index?
Call enumerated() on the array. It gives you a tuple with the index and the value:
let fruits = ["apple", "banana", "cherry"]
for (index, fruit) in fruits.enumerated() {
print("\(index): \(fruit)")
}
// 0: apple
// 1: banana
// 2: cherry
This is much cleaner than managing a counter variable yourself.
Iterating over strings
A string is a sequence of characters, so you can loop over it directly:
for letter in "Swift" {
print(letter)
}
// S, w, i, f, t
Each letter is a Character value.
Iterating over dictionaries
A dictionary gives you a (key, value) tuple on each iteration:
let ages = ["Flavio": 40, "Roger": 8, "Syd": 5]
for (name, age) in ages {
print("\(name) is \(age) years old")
}
One thing to remember: dictionaries have no defined order. Run this twice and the lines can come out in a different sequence.
Filtering with where
You can add a where clause to skip elements that don’t match a condition:
for number in 1...10 where number % 2 == 0 {
print(number) // 2, 4, 6, 8, 10
}
This reads better than putting an if inside the loop body, because the filter is visible right in the loop declaration.
Custom steps with stride
Ranges always move by 1. When you need a different step, use stride(from:to:by:):
for number in stride(from: 0, to: 10, by: 2) {
print(number) // 0, 2, 4, 6, 8
}
The to: value is excluded. If you want to include it, use stride(from:through:by:) instead:
for number in stride(from: 0, through: 10, by: 2) {
print(number) // 0, 2, 4, 6, 8, 10
}
You can also stride backwards with a negative by: value.
When you don’t need the value
If you just want to repeat something a number of times and don’t care about the counter, use an underscore:
for _ in 1...3 {
print("Hello!")
}
The _ tells Swift (and whoever reads your code) that the value is intentionally ignored.
break and continue
Both work inside for-in loops. break exits the loop, continue skips to the next iteration:
for number in 1...10 {
if number == 4 {
break
}
print(number) // 1, 2, 3
}
I cover them in more detail in the while loop tutorial, and they behave the same way here.
Related posts about swift: