Day 06
Day 06 êŽë š
Loops
Loops are one of the things that make computers so utterly brilliant: the ability to repeat some simple task billions of times every second.
Of course, what goes in those loops is down to you: you might be adding some numbers, you might be reading some sensor data, or you might be redrawing the screen 120 times a second. As Craig Bruce said, âitâs hardware that makes a machine fast, but itâs software that makes a fast machine slow.â
Today you have three tutorials to work through, plus a summary and a checkpoint. Once youâve completed each video you can read the optional extra section, and thereâs a short test to help make sure youâve understood what was taught.
1. How to use a for loop to repeat work
1. How to use a for loop to repeat work
Computers are really great at doing repetitive work, and Swift makes it easy to repeat some code a fixed number of times, or once for every item in an array, dictionary, or set.
Letâs start with something simple: if we have an array of strings, we can print each string out like this:
let platforms = ["iOS", "macOS", "tvOS", "watchOS"]
for os in platforms {
print("Swift works great on \(os).")
}
That loops over all the items in platforms
, putting them one by one into os
. We havenât created os
elsewhere; itâs created for us as part of the loop and made available only inside the opening and closing braces.
Inside the braces is the code we want to run for each item in the array, so the code above will print four lines â one for each loop item. First it puts âiOSâ in there then calls print()
, then it puts âmacOSâ in there and calls print()
, then âtvOSâ, then âwatchOSâ.
To make things easier to understand, we give these things common names:
- We call the code inside the braces the loop body
- We call one cycle through the loop body a loop iteration.
- We call
os
the loop variable. This exists only inside the loop body, and will change to a new value in the next loop iteration.
I should say that the name os
isnât special â we could have written this instead:
for name in platforms {
print("Swift works great on \(name).")
}
Or even this:
for rubberChicken in platforms {
print("Swift works great on \(rubberChicken).")
}
The code will still work exactly the same.
In fact, Xcode is really smart here: if you write for plat
it will recognize that thereâs an array called platforms
, and offer to autocomplete all of for platform in platforms
â it recognizes that platforms
is plural and suggests the singular name for the loop variable. When you see Xcodeâs suggestion appear, press Return to select it.
Rather than looping over an array (or set, or dictionary â the syntax is the same!), you can also loop over a fixed range of numbers. For example, we could print out the 5 times table from 1 through 12 like this:
for i in 1...12 {
print("5 x \(i) is \(5 * i)")
}
A couple of things are new there, so letâs pause and examine them:
- I used the loop variable
i
, which is a common coding convention for ânumber youâre counting withâ. If youâre counting a second number you would usej
, and if youâre counting a third you would usek
, but if youâre counting a fourth maybe you should pick better variable names. - The
1...12
part is a range, and means âall integer numbers between 1 and 12, as well as 1 and 12 themselves.â Ranges are their own unique data type in Swift.
So, when that loop first runs i
will be 1, then it will be 2, then 3, etc, all the way up to 12, after which the loop finishes.
You can also put loops inside loops, called nested loops, like this:
for i in 1...12 {
print("The \(i) times table:")
for j in 1...12 {
print(" \(j) x \(i) is \(j * i)")
}
`print()`
}
That shows off a couple of other new things, so again letâs pause and look closer:
- Thereâs now a nested loop: we count from 1 through 12, and for each number inside there we count 1 through 12 again.
- Using
print()
by itself, with no text or value being passed in, will just start a new line. This helps break up our output so it looks nicer on the screen. So, when you seex...y
you know it creates a range that starts at whatever numberx
is, and counts up to and including whatever numbery
is.
Swift has a similar-but-different type of range that counts up to but excluding the final number: ..<
. This is best seen in code:
for i in 1...5 {
print("Counting from 1 through 5: \(i)")
}
`print()`
for i in 1..<5 {
print("Counting 1 up to 5: \(i)")
}
When that runs, it will print for numbers 1, 2, 3, 4, 5 in the first loop, but only numbers 1, 2, 3, and 4 in the second. I pronounce 1...5
as âone through fiveâ, and 1..<5
as âone up to five,â and youâll see similar wording elsewhere in Swift.
Tip: ..<
is really helpful for working with arrays, where we count from 0 and often want to count up to but excluding the number of items in the array.
Before weâre done with for
loops, thereâs one more thing I want to mention: sometimes you want to run some code a certain number of times using a range, but you donât actually want the loop variable â you donât want the i
or j
, because you donât use it.
In this situation, you can replace the loop variable with an underscore, like this:
var lyric = "Haters gonna"
for _ in 1...5 {
lyric += " hate"
}
print(lyric)
(Yes, thatâs a Taylor Swift lyric from Shake It Off, written in Swift.)
1. How to use a for loop to repeat work - Additional
Optional: Why does Swift use underscores with loops? Optional: Why does Swift have two range operators? Test: For loops
2. How to use a while loop to repeat work
2. How to use a while loop to repeat work
Swift has a second kind of loop called while
: provide it with a condition, and a while
loop will continually execute the loop body until the condition is false.
Although youâll still see while
loops from time to time, they arenât as common as for
loops. As a result, I want to cover them so you know they exist, but letâs not dwell on them too long, okay?
Hereâs a basic while
loop to get us started:
var countdown = 10
while countdown > 0 {
print("\(countdown)âŠ")
countdown -= 1
}
print("Blast off!")
That creates an integer counter starting at 10, then starts a while
loop with the condition countdown > 0
. So, the loop body â printing the number and subtracting 1 â will run continually until countdown
is equal to or below 0, at which point the loop will finish and the final message will be printed.
while
loops are really useful when you just donât know how many times the loop will go around. To demonstrate this, I want to introduce you to a really useful piece of functionality that Int
and Double
both have: random(in:)
. Give that a range of numbers to work with, and it will send back a random Int
or Double
somewhere inside that range.
For example, this creates a new integer between 1 and 1000
let id = Int.random(in: 1...1000)
And this creates a random decimal between 0 and 1:
let amount = Double.random(in: 0...1)
We can use this functionality with a while
loop to roll some virtual 20-sided dice again and again, ending the loop only when a 20 is rolled â a critical hit for all you Dungeons & Dragons players out there.
Hereâs the code to make that happen:
// create an integer to store our roll
var roll = 0
// carry on looping until we reach 20
while roll != 20 {
// roll a new dice and print what it was
roll = Int.random(in: 1...20)
print("I rolled a \(roll)")
}
// if we're here it means the loop ended â we got a 20!
print("Critical hit!")
Youâll find yourself using both for
and while
loops in your own code: for
loops are more common when you have a finite amount of data to go through, such as a range or an array, but while
loops are really helpful when you need a custom condition.
2. How to use a while loop to repeat work - Additional
Optional: When should you use a while loop? Test: While loops
3. How to skip loop items with break and continue
3. How to skip loop items with break and continue
Swift gives us two ways to skip one or more items in a loop: continue
skips the current loop iteration, and break
skips all remaining iterations. Like while
loops these are sometimes used, but in practice much less than you might think.
Letâs look at them individually, starting with continue
. When youâre looping over an array of data, Swift will take out one item from the array and execute the loop body using it. If you call continue
inside that loop body, Swift will immediately stop executing the current loop iteration and jump to the next item in the loop, where it will carry on as normal. This is commonly used near the start of loops, where you eliminate loop variables that donât pass a test of your choosing.
Hereâs an example:
let filenames = ["me.jpg", "work.txt", "sophie.jpg", "logo.psd"]
for filename in filenames {
if filename.hasSuffix(".jpg") == false {
continue
}
print("Found picture: \(filename)")
}
That creates an array of filename strings, then loops over each one and checks to make sure it has the suffix â.jpgâ â that itâs a picture. continue
is used with all the filenames failing that test, so that the rest of the loop body is skipped.
As for break
, that exits a loop immediately and skips all remaining iterations. To demonstrate this, we could write some code to calculate 10 common multiples for two numbers:
let number1 = 4
let number2 = 14
var multiples = [Int]()
for i in 1...100_000 {
if i.isMultiple(of: number1) && i.isMultiple(of: number2) {
multiples.append(i)
if multiples.count == 10 {
break
}
}
}
print(multiples)
That does quite a lot:
- Create two constants to hold two numbers.
- Create an integer array variable that will store common multiples of our two numbers.
- Count from 1 through 100,000, assigning each loop variable to
i
. - If
i
is a multiple of both the first and second numbers, append it to the integer array. - Once we hit 10 multiples, call
break
to exit the loop. - Print out the resulting array.
So, use continue
when you want to skip the rest of the current loop iteration, and use break
when you want to skip all remaining loop iterations.
3. How to skip loop items with break and continue - Additional
Optional: Why would you want to exit a loop? Optional: When to use break and when to use continue Test: Exiting loops
4. Summary: Conditions and loops
4. Summary: Conditions and loops
Weâve covered a lot about conditions and loops in the previous chapters, so letâs recap:
- We use
if
statements to check a condition is true. You can pass in any condition you want, but ultimately it must boil down to a Boolean. - If you want, you can add an
else
block, and/or multipleelse if
blocks to check other conditions. Swift executes these in order. - You can combine conditions using
||
, which means that the whole condition is true if either subcondition is true, or&&
, which means the whole condition is true if both subconditions are true. - If youâre repeating the same kinds of check a lot, you can use a
switch
statement instead. These must always be exhaustive, which might mean adding a default case. - If one of your
switch
cases usesfallthrough
, it means Swift will execute the following case afterwards. This is not used commonly. - The ternary conditional operator lets us check WTF: What, True, False. Although itâs a little hard to read at first, youâll see this used a lot in SwiftUI.
for
loops let us loop over arrays, sets, dictionaries, and ranges. You can assign items to a loop variable and use it inside the loop, or you can use underscore,_
, to ignore the loop variable.while
loops let us craft custom loops that will continue running until a condition becomes false.- We can skip some or all loop items using
continue
orbreak
respectively.
Thatâs another huge chunk of new material, but with conditions and loops you now know enough to build some really useful software â give it a try!
5. Checkpoint 3
5. Checkpoint 3
Now that youâre able to use conditions and loops, Iâd like you to try a classic computer science problem. Itâs not hard to understand, but it might take you a little time to solve depending on your prior experience!
The problem is called fizz buzz, and has been used in job interviews, university entrance tests, and more for as long as I can remember. Your goal is to loop from 1 through 100, and for each number:
- If itâs a multiple of 3, print âFizzâ
- If itâs a multiple of 5, print âBuzzâ
- If itâs a multiple of 3 and 5, print âFizzBuzzâ
- Otherwise, just print the number.
So, here are some example values you should have when your code runs:
- 1 should print â1â
- 2 should print â2â
- 3 should print âFizzâ
- 4 should print â4â
- 5 should print âBuzzâ
- 6 should print âFizzâ
- 7 should print â7â
- âŠ
- 15 should print âFizzBuzzâ
- âŠ
- 100 should print âBuzzâ
Before you start: This problem seems extremely simple, but many, many developers struggle to solve it. Iâve seen it happen personally, so donât stress about it â just trying to solve the problem already teaches you about it.
You already know everything you need to solve that problem, but if youâd like some hints then Iâll add some below.
Please go ahead and try building the playground now.
Still here? Okay, here are some hints:
- You can check whether one number is a multiple of another by using
.isMultiple(of:)
. For example,i.isMultiple(of: 3)
. - In this instance you need to check for 3 and 5 first because itâs the most specific, then 3, then 5, and finally have an
else
block to handle all other numbers. - You can either use
&&
to check for numbers that are multiples of 3 and 5, or have a nestedif
statement. - You need to count from 1 through 100, so use
...
rather than..<
.