# Lesson 5 – Counting and Repeating Steps with Swift Loops and Ranges

## Check whether ranges contain specific values with the pattern matching operator

Ranges are intervals of both positive and negative numbers. There are five types of *ranges* in Swift.

1 2 3 4 5 |
0...10 ~= 10 // true 0..<10 ~= 10 // false 0... ~= 10 // true ...0 ~= 0 // true ..<0 ~= 0 // false |

The
~= operator is a *pattern matching* operator. It returns
true if the range on its left side contains the value on its right side and
false** **otherwise.

Here is how each type of range works:

1 |
0...10 ~= 10 // true |

- The
left…right range is the
*closed at both sides*type. It contains both the left and right sides of the range and all the numbers in-between.

1 |
0..<10 ~= 10 // false |

- The
left..<right range is the
*half-open at its right side*type. It contains only the left side of the range and all of the numbers between the left and right sides of the range (but not the right side of the range).

1 |
0... ~= 10 // true |

- The
left… range is the
*one-sided closed at its left side*type. It contains the left side of the range and all of the other numbers from there onwards.

1 |
...0 ~= 0 // true |

- The
…right range is the
*one-sided closed at its right side*type. It contains the right side of the range and all of the other numbers leading up to it.

1 |
..<0 ~= 0 // false |

- The
..<right range is the
*one-sided half-open at its right side*type. It contains all numbers up to (but not including) the right side of the range.

## Cover all possible cases in switch statements with ranges

Switch statements use the pattern matching operator to check whether ranges contain specific values.

1 2 3 4 5 6 7 |
let number = 10 switch number { case ..<0: print("Negative number") case 0..<10: print("Digit") case 10...: print("Positive number") default: break } |

Each case statement checks whether its corresponding range contains the value of the number constant. Both of the one-sided half-open ranges and the closed range make sure that all possible numbers are covered, so the switch statement is exhaustive in this case.

The default case is still needed because the compiler doesn’t know that the case statements handle all possible number values. Because of this, the break statement exits the default case.

The left side of both half-open ranges and the closed range both sides type must **always** be less than or equal to their right side.

1 |
10...0 ~= 10 |

The compiler flags a runtime error for the above code because the left side of the range is greater than its right side.

Click the playground’s sidebar buttons to see the error’s stack trace.

Switch the left side of the range with its right side to fix the error.

1 |
0...10 ~= 10 // true |

The range is now valid, and there is no error.

## Repeat steps in loops with ranges

Loops use both half-open ranges and closed ranges of whole numbers that aren’t one-sided to repeat certain things a set number of times.

1 2 3 4 |
var sum = 0 for digit in 1...9 { sum += digit } |

The for in loop uses a closed range of digits to compute the sum of all the digits. Each iteration adds its corresponding digit to the sum variable.

The loop’s body contains what happens during each iteration* *and is placed between curly braces.

Here is what goes on for each iteration of the loop:

- digit = 1, sum = 1
- digit = 2, sum = 3
- digit = 3, sum = 6
- digit = 4, sum = 10
- digit = 5, sum = 15
- digit = 6, sum = 21
- digit = 7, sum = 28
- digit = 8, sum = 36
- digit = 9, sum = 45

The number of iterations in the loop is the same as the number of digits in the range, and the sum variable contains the sum of all digits after the last iteration.

Both closed ranges and half-open ranges of whole numbers that aren’t one-sided ensure the loop finishes when there are no more numbers in the range.

The playground’s sidebar can display the intermediate values of the sum variable in two different ways.

You can choose the Value History* *option from the playground’s sidebar to see the value of the
sum variable for each loop’s iteration.

Alternatively, you can select the Graph option from the playground’s sidebar to see the sum variable values for all iterations of the loop on a diagram.

## Solve complex problems with conditions and loops

Loops use conditions to create more advanced logic during iterations.

1 2 3 4 5 6 7 8 9 |
var even = 0 var odd = 0 for digit in 1...9 { if digit % 2 == 0 { even += digit } else { odd += digit } } |

Each loop iteration adds its corresponding digit either to the even variable if it is even or to the odd variable otherwise.

Here is what happens for each loop’s iteration:

- digit = 1, even = 0, odd = 1
- digit = 2, even = 2, odd = 1
- digit = 3, even = 2, odd = 4
- digit = 4, even = 6, odd = 4
- digit = 5, even = 6, odd = 9
- digit = 6, even = 12, odd = 9
- digit = 7, even = 12, odd = 16
- digit = 8, even = 20, odd = 16
- digit = 9, even = 20, odd = 25

The loop goes through the closed range of digits, and either the even variable or the odd variable is updated during each iteration.

## Exit loops and skip loop iterations with break and continue statements

Imagine you are playing a game with multiple levels. This is what the game’s loop would look like:

1 2 3 4 |
let levels = 10 for _ in 1...levels { print("Play level.") } |

The game’s loop uses a closed range to ensure that you automatically advance to the next level once the current level is completed.

Imagine you need to pay for some of the levels in the game. The underscore doesn’t track which level you are playing at what time. This means you don’t know whether you are playing either a free level or a bonus level.

You can improve the game’s loop by changing the code to show the current level of the game first.

1 2 3 4 |
let levels = 10 for level in 1...levels { print("Play level \(level).") } |

You can now play all of the game’s levels even if you haven’t bought them all yet. You can fix this by ending the game after you have played all of its free levels.

1 2 3 4 5 6 7 8 9 |
let levels = 10 let freeLevels = 4 for level in 1...levels { print("Play level \(level).") if level == freeLevels { print("You have played all \(freeLevels) free levels. Buy the game to play the other \(levels - freeLevels) levels.") break } } |

The break statement exits the game’s loop once you have played all the free levels.

The game also has a bonus free level which you can skip if you want to focus on the other free levels of the game instead.

1 2 3 4 5 6 7 8 9 |
let levels = 10 let bonusLevel = 3 for level in 1...levels { if level == bonusLevel { print("Skip bonus level \(bonusLevel).") continue } print("Play level \(level).") } |

The continue statement finishes the current iteration of the loop if its corresponding game’s level is a bonus one and automatically advances to the next loop’s iteration instead.

Both break and continue statements can be used in the very same loop:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let levels = 10 let freeLevels = 4 let bonusLevel = 3 for level in 1...levels { if level == bonusLevel { print("Skip bonus level \(bonusLevel).") continue } print("Play level \(level).") if level == freeLevels { print("You have played all \(freeLevels) free levels. Buy the game to play the other \(levels - freeLevels) levels.") break } } |

This is the complete loop for now. You will improve it more in the next section.

## Create complex logic with nested loops

Suppose that the game you are playing has multiple challenges for each level. This is what the game’s loop would look like:

1 2 3 4 5 6 7 8 |
let levels = 10 let challenges = 10 for _ in 1...levels { print("Play level.") for _ in 1...challenges { print("Play level's challenge.") } } |

The first loop goes through all of the game’s levels, and the second loop goes through all of the current level’s challenges. This ensures that you only advance to the next level once you have completed all of the current level’s challenges.

The underscore doesn’t keep track of which challenge or level you are playing at what time. This means that you don’t know whether you are playing a free level, a bonus level, or a challenge.

You can improve the game’s loop by showing the current level of the game and the current challenge of the level.

1 2 3 4 5 6 7 8 |
let levels = 10 let challenges = 10 for level in 1...levels { print("Play level \(level).") for challenge in 1...challenges { print("Play challenge \(challenge) of level \(level).") } } |

You can now play all of the game’s levels and the current level’s challenges even if you haven’t bought the game yet.

You can fix this by ending the game after you have played all of its free levels while skipping a bonus free level of the game along the way.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
let levels = 10 let freeLevels = 4 let bonusLevel = 3 let challenges = 10 for level in 1...levels { if level == bonusLevel { print("Skip bonus level \(bonusLevel).") continue } print("Play level \(level).") for challenge in 1...challenges { print("Play challenge \(challenge) of level \(level).") } if level == freeLevels { print("You have played all \(freeLevels) free levels. Buy the game to play the other \(levels - freeLevels) levels.") break } } |

Both break and continue statements are used inside the level’s outer loop as before. You can add the very same logic to the challenge’s inner loop to finish the current level after you have played all of its free challenges. You can also skip any bonus free challenge that the current free level has along the way.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
let levels = 10 let challenges = 10 let freeLevels = 4 let freeChallenges = 4 let bonusLevel = 3 let bonusChallenge = 3 for level in 1...levels { if level == bonusLevel { print("Skip bonus level \(bonusLevel).") continue } print("Play level \(level).") for challenge in 1...challenges { if challenge == bonusChallenge { print("Skip bonus challenge \(bonusChallenge) of level \(level).") continue } print("Play challenge \(challenge) of level \(level).") if challenge == freeChallenges { print("You have played all \(freeChallenges) free challenges of level \(level). Buy the game to play the other \(challenges - freeChallenges) challenges of level \(level).") break } } if level == freeLevels { break } } |

Both nested loops now have break and continue statements. The game’s loop is complete.

## Register to get more exclusive free content

You can follow the entire course for free, with no registration required. Creating a free account gives you these extra benefits:

- Enroll in the course and track your progress;
- Download a free Swift cheat sheet;
- Get access to other exclusive guides and courses available only to registered users.