# Swift Iterating with stride: Forward and Reverse Looping

Source: https://devdocs10.com/articles/swift/swift-stride  
By Murat Bo · Published 2026-05-12 · DevDocs10 (https://devdocs10.com)

Swift ranges like `0...10` are great for counting one step at a time, but many real loops need a different step size. You might want to count by 2, loop backward, generate time intervals, or stop just before a final value. This article explains how to iterate with `stride` in Swift, when to use `to` versus `through`, and how to avoid the mistakes that often confuse beginners.

> **Quick answer:** Use `stride(from:to:by:)` when the end value should be excluded, and use `stride(from:through:by:)` when the end value should be included if the step reaches it. `stride` is the standard Swift way to loop with a custom step size, including reverse loops.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You'll understand this better if you know basic Swift syntax, how `for-in` loops work, and how numeric types like `Int` and `Double` are used.

## 1. What Is Iterating with stride?

Iterating with `stride` means producing a sequence of values that moves from a starting value toward an ending value using a fixed step size. Instead of advancing by 1 automatically, you choose the amount to move each time.

- `stride` is useful when a normal range is not enough.
- It can move forward with a positive step, such as 0, 2, 4, 6.
- It can move backward with a negative step, such as 10, 8, 6, 4.
- Swift provides two common forms: `stride(from:to:by:)` and `stride(from:through:by:)`.
- The difference between them is whether the ending value is excluded or included.

A regular range like `1...5` works well when you want every number in order. But if you need every second number, every fifth index, or a reverse countdown, `stride` is usually the right tool.

> A common comparison is `range` versus `stride`. Ranges are simpler for step-by-1 iteration, while `stride` is designed for custom increments or decrements.

## 2. Why Iterating with stride Matters

Custom-step loops appear often in real Swift code. Even if beginner examples focus on counting from 1 to 10, production code frequently needs more control.

- Processing every nth item in a collection index sequence.
- Creating countdowns and reverse traversals.
- Generating chart axis values or measurement intervals.
- Running simulations at fixed time steps.
- Skipping unnecessary iterations for performance or clarity.

Using `stride` also makes intent clearer. A loop that says “move by 5” is easier to understand than a loop that counts every value and manually ignores most of them.

You should not use `stride` when a simple range already expresses the logic naturally. If you just need every integer from 1 to 5, a normal range is shorter and easier to read.

## 3. Basic Syntax

### Using stride(from:to:by:)

This form starts at one value, moves by a fixed amount, and stops before reaching the end value.

```swift
for number in stride(from: 0, to: 10, by: 2) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
```

This prints `0`, `2`, `4`, `6`, and `8`. It does not print `10` because `to` is exclusive.

### Using stride(from:through:by:)

This form includes the end value if the stepping lands on it exactly.

```swift
for number in stride(from: 0, through: 10, by: 2) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
10
```

This prints `0`, `2`, `4`, `6`, `8`, and `10`.

### Using a negative step

To count backward, the step must be negative.

```swift
for countdown in stride(from: 5, through: 1, by: -1) {
    print(countdown)
}
```

Output (tested with Swift 6.4):

```text
5
4
3
2
1
```

This produces a reverse loop from 5 down to 1.

So the core idea is simple:

- `from` is the starting value.
- `to` or `through` is the target boundary.
- `by` is the step size.

## 4. Step-by-Step Examples

### Example 1: Looping through even numbers

This example prints only even numbers from 0 up to, but not including, 10.

```swift
for value in stride(from: 0, to: 10, by: 2) {
    print(value)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
```

This is clearer than looping through every number and checking whether it is even.

### Example 2: Inclusive counting with through

If you need the ending value included, use `through` instead of `to`.

```swift
for value in stride(from: 0, through: 10, by: 5) {
    print("Checkpoint: \(value)")
}
```

Output (tested with Swift 6.4):

```text
Checkpoint: 0
Checkpoint: 5
Checkpoint: 10
```

This prints checkpoints at 0, 5, and 10. It shows the inclusive behavior clearly.

### Example 3: Reverse countdown

A negative step lets you count down instead of up.

```swift
for seconds in stride(from: 10, through: 0, by: -1) {
    print("\(seconds)...")
}
print("Go!")
```

Output (tested with Swift 6.4):

```text
10...
9...
8...
7...
6...
5...
4...
3...
2...
1...
0...
Go!
```

This is a common pattern for timers, countdown displays, and reverse traversal.

### Example 4: Working with decimal values

`stride` can also be used with floating-point values such as `Double`.

```swift
for temperature in stride(from: 18.0, through: 20.0, by: 0.5) {
    print("Set to \(temperature)°C")
}
```

Output (tested with Swift 6.4):

```text
Set to 18.0°C
Set to 18.5°C
Set to 19.0°C
Set to 19.5°C
Set to 20.0°C
```

This creates values 18.0, 18.5, 19.0, 19.5, and 20.0. It is useful for measurement-based iteration, though floating-point precision needs care, which we will cover later.

### Example 5: Iterating over array indexes with a step

Sometimes you want every second item in an array by index.

```swift
let names = ["Ana", "Ben", "Chris", "Dina", "Eli"]

for index in stride(from: 0, to: names.count, by: 2) {
    print(names[index])
}
```

Output (tested with Swift 6.4):

```text
Ana
Chris
Eli
```

This prints the values at indexes 0, 2, and 4. Using `to: names.count` is important because array indexes stop before the count.

## 5. Practical Use Cases

- Showing every 5th minute in a scheduling or calendar tool.
- Building a countdown before a game starts.
- Sampling every nth element from a data set.
- Generating tick marks for a graph or progress scale.
- Looping backward through indexes when removing items carefully.
- Testing logic at fixed intervals, such as 0.0, 0.25, 0.5, and 0.75.

## 6. Common Mistakes

### Mistake 1: Using to when you meant through

This is one of the most common beginner problems. The loop seems correct, but the final value never appears.

**Problem:** `to` excludes the ending value, so this code stops before 10 even though the step size would otherwise reach it.

```swift
for number in stride(from: 0, to: 10, by: 2) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
```

**Fix:** Use `through` when the ending value should be included if the sequence lands on it.

```swift
for number in stride(from: 0, through: 10, by: 2) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
10
```

The corrected version works because `through` uses an inclusive boundary.

### Mistake 2: Using a positive step in a reverse loop

When counting down, the step must move toward the ending value. A positive step cannot do that.

**Problem:** This loop tries to go from 10 down to 0 with a positive step, so it does not move in the correct direction and will not produce the intended sequence.

```swift
for number in stride(from: 10, through: 0, by: 1) {
    print(number)
}
```

**Fix:** Use a negative step when the start is greater than the end.

```swift
for number in stride(from: 10, through: 0, by: -1) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
10
9
8
7
6
5
4
3
2
1
0
```

The corrected version works because each step moves closer to the lower boundary.

### Mistake 3: Going out of bounds when using array indexes

Array loops often fail when the end value is treated as a valid index. In Swift, the final valid index is one less than `count`.

**Problem:** This code includes `items.count` as an index by using `through`, which can cause a runtime crash with an index out of range error.

```swift
let items = ["A", "B", "C"]

for index in stride(from: 0, through: items.count, by: 1) {
    print(items[index])
}
```

**Fix:** Use `to: items.count` so the loop stops before the invalid final index.

```swift
let items = ["A", "B", "C"]

for index in stride(from: 0, to: items.count, by: 1) {
    print(items[index])
}
```

Output (tested with Swift 6.4):

```text
A
B
C
```

The corrected version works because array indexes run from 0 up to, but not including, `count`.

### Mistake 4: Expecting floating-point stride values to behave perfectly

Floating-point numbers like `0.1` cannot always be represented exactly in binary. That can produce surprising output in some calculations.

**Problem:** This code may produce values with tiny precision differences, so direct equality checks can fail or printed results can look unexpected.

```swift
for value in stride(from: 0.0, through: 1.0, by: 0.1) {
    if value == 0.3 {
        print("Found exactly 0.3")
    }
}
```

**Fix:** Avoid relying on exact equality with floating-point stride values. Compare within a small tolerance or use integer steps and convert when needed.

```swift
for step in stride(from: 0, through: 10, by: 1) {
    let value = Double(step) / 10.0
    if abs(value - 0.3) < 0.0001 {
        print("Close to 0.3")
    }
}
```

Output (tested with Swift 6.4):

```text
Close to 0.3
```

The corrected version works because it avoids depending on exact binary representation of decimal fractions.

## 7. Best Practices

### Practice 1: Choose to or through deliberately

Beginners often pick one form without thinking about the boundary. A better approach is to decide whether the ending value belongs in the sequence.

```swift
// Excludes 12
for hour in stride(from: 0, to: 12, by: 3) {
    print(hour)
}

// Includes 12
for hour in stride(from: 0, through: 12, by: 3) {
    print(hour)
}
```

Output (tested with Swift 6.4):

```text
0
3
6
9
0
3
6
9
12
```

This practice makes loops easier to reason about and prevents off-by-one errors.

### Practice 2: Match the step direction to the loop direction

Make the step clearly positive when moving upward and clearly negative when moving downward.

```swift
// Preferred forward loop
for score in stride(from: 0, through: 100, by: 20) {
    print(score)
}

// Preferred reverse loop
for score in stride(from: 100, through: 0, by: -20) {
    print(score)
}
```

Output (tested with Swift 6.4):

```text
0
20
40
60
80
100
100
80
60
40
20
0
```

This keeps the loop behavior obvious and avoids empty or incorrect iteration.

### Practice 3: Prefer stride over filtering every value manually

If the loop itself should skip values, express that in the iteration rather than inside the body.

```swift
// Less preferred
for number in 0...20 {
    if number % 2 == 0 {
        print(number)
    }
}

// Preferred
for number in stride(from: 0, through: 20, by: 2) {
    print(number)
}
```

Output (tested with Swift 6.4):

```text
0
2
4
6
8
10
12
14
16
18
20
0
2
4
6
8
10
12
14
16
18
20
```

The preferred version better communicates that only even numbers are part of the loop.

## 8. Limitations and Edge Cases

- `stride(from:through:by:)` includes the end only if the stepping lands on it exactly.
- Floating-point iteration can show precision surprises, especially with decimal step sizes like `0.1`.
- Using `through: array.count` with array indexing can cause an `index out of range` crash.
- If the step direction does not match the start and end values, the loop may produce no values.
- `stride` is best for evenly spaced steps. If the next value depends on changing logic, a `while` loop may be a better fit.
- For simple step-by-1 integer loops, ranges are usually shorter and easier to read than `stride`.

## 9. Practical Mini Project

This small program prints time marks every 15 minutes across one hour, then performs a reverse countdown. It combines inclusive and exclusive boundaries in a realistic way.

```swift
let interval = 15

print("Quarter-hour marks:")
for minute in stride(from: 0, through: 60, by: interval) {
    print("Minute \(minute)")
}

print("")
print("Countdown:")
for seconds in stride(from: 5, through: 0, by: -1) {
    print("\(seconds)")
}
print("Start!")
```

Output (tested with Swift 6.4):

```text
Quarter-hour marks:
Minute 0
Minute 15
Minute 30
Minute 45
Minute 60

Countdown:
5
4
3
2
1
0
Start!
```

The first loop uses `through` because 60 should appear as the final quarter-hour mark. The second loop shows reverse iteration with a negative step. Together they demonstrate how `stride` handles both forward and backward loops cleanly.

## 10. Key Points

- Use `stride` when you need a custom step size in a loop.
- `stride(from:to:by:)` excludes the ending value.
- `stride(from:through:by:)` includes the ending value if the step reaches it.
- Use a negative `by` value for reverse loops.
- When indexing arrays, use `to: array.count` to avoid out-of-range access.
- Be careful with floating-point stride values because decimal precision can be surprising.

## 11. Practice Exercise

Write a Swift program that does all of the following:

- Prints the multiples of 3 from 3 through 15.
- Prints a reverse countdown from 4 to 0.
- Stores an array of five strings and prints every second item using `stride`.

**Expected output:** Multiples of 3, then the countdown, then array elements at indexes 0, 2, and 4.

**Hint:** You will need one forward loop with `through`, one reverse loop with a negative step, and one array-index loop with `to: items.count`.

```swift
let words = ["red", "blue", "green", "yellow", "purple"]

print("Multiples of 3:")
for number in stride(from: 3, through: 15, by: 3) {
    print(number)
}

print("Countdown:")
for number in stride(from: 4, through: 0, by: -1) {
    print(number)
}

print("Every second word:")
for index in stride(from: 0, to: words.count, by: 2) {
    print(words[index])
}
```

Output (tested with Swift 6.4):

```text
Multiples of 3:
3
6
9
12
15
Countdown:
4
3
2
1
0
Every second word:
red
green
purple
```

## 12. Final Summary

Swift's `stride` functions give you precise control over iteration. They let you move forward or backward by a chosen amount, which makes them ideal for custom counting, sampling values, reverse loops, and index-based stepping. The most important distinction is that `to` excludes the end value, while `through` includes it when the step lands on it.

You also saw the most common pitfalls: choosing the wrong boundary, using the wrong step direction, indexing arrays incorrectly, and expecting floating-point values to behave exactly like decimal math on paper. If you practice reading loop boundaries carefully, `stride` becomes a simple and powerful part of everyday Swift. A good next step is to compare `stride` with standard ranges and `while` loops so you can choose the clearest loop style for each task.
