- Declare a
for
loop to perform a hardcoded set of iterations. - Use
if
,else if
, andelse
statements to define various behaviors based upon the loop's counter variable. - Move the loop's iteration logic from hardcoded values into variables instead.
- Attempt your own solution to the FizzBuzz exercise that repeats neither the conditional logic nor instructions.
- Follow best practice by using variables instead of "magic numbers" in the conditional logic.
FizzBuzz is a classic programmer's exercise. It originated from a children's word game used to teach division. The rules are simple: a sequence of numbers is counted out, but every number divisible by three is replaced with "Fizz", every number divisible by five is replaced with "Buzz", and every number divisible by both three and five is replaced with "Fizz" and "Buzz". A correct recitation of the sequence would follow this pattern:
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz,
16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz,
31 ...
In this code-along, we're going to use the FizzBuzz exercise to practice writing a for
loop.
Note: We will not be writing an ideal implementation of FizzBuzz.
Fork and clone this lab. Open the objc-fizzbuzz.xcodeproj
file and navigate to the FISAppDelegate.m
file. Write your code inside the application:didFinishLaunchingWithOptions:
methods before the return YES;
statement.
1 — Declare a for
loop that will iterate 100
times. At which value should the counter begin in respect to FizzBuzz?
Hint: The range of the loop's counter should be 1
to 100
, not 0
to 99
.
for (NSUInteger i = 1; i <= 100; i++) {
}
2 — Begin the loop's implementation by printing i
to the console:
for (NSUInteger i = 1; i <= 100; i++) {
NSLog(@"%lu", i);
}
This will print the integers 1
through 100
.
3 — Instead of formatting directly into the NSLog()
, let's create local string variable called result
which we can use to set the loop's output based on different conditions. Initialize result
to an empty string; on a separate line reassign it to the interpolated string containing the loop's counter by using NSString
's stringWithFormat:
method; finally, use the result
string in the NSLog()
instead:
for (NSUInteger i = 1; i <= 100; i++) {
NSString *result = @"";
result = [NSString stringWithFormat:@"%lu", i];
NSLog(@"%@", result);
}
This should still print the integers 1
through 100
.
4 — Now, let's have the loop print Fizz
on every third iteration. We can accomplish this by using an if
statement and an else
statement. In the if
statement's conditional, use the modulus operator (%
) to determine if the remainder of dividing the value of i
by 3
is equal to 0
. If this evaluates to YES
, the if
statement should set result
to @"Fizz"
. If not, the else
statement (which is the "default" action) should set result
to the interpolated string of i
that we wrote in step 3:
for (NSUInteger i = 1; i <= 100; i++) {
NSString *result = @"";
if (i % 3 == 0) {
result = @"Fizz";
}
else {
result = [NSString stringWithFormat:@"%lu", i];
}
NSLog(@"%@", result);
}
This should now print the integers 1
through 100
with every multiple of three (3
) replaced by the word "Fizz":
1
2
Fizz
4
5
Fizz
7
8
Fizz
10
11
Fizz
13
14
Fizz
...
5 — Now let's have the loop print "Buzz" on every fifth iteration. Insert an else if
statement that determines of the remainder (%
) of dividing the current value of i
by 5
is equal to 0
. If so, then set result
to @"Buzz"
:
for (NSUInteger i = 1; i <= 100; i++) {
NSString *result = @"";
if (i % 3 == 0) {
result = @"Fizz";
}
else if (i % 5 == 0) {
result = @"Buzz";
}
else {
result = [NSString stringWithFormat:@"%lu", i];
}
NSLog(@"%@", result);
}
This should now print the integers 1
through 100
with every multiple of three (3
) replaced by the word "Fizz", and every multiple of five (5
) that is not also a multiple of three replaced by the word "Buzz":
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz
...
So, why does every multiple of fifteen (15
) still print "Fuzz"? Remember that an else if
statement only has a chance to run if none of the if
or else if
statements before it runs.
6 — Let's instead start the switch block with an if
statement that evaluates whether or not the current value of i
is a multiple of both three (3
) and five (5
). We can use the same remainder logic as the other two evaluations but combine them with "and" logical operator (&&
). If both of these conditions pass simultaneously, we can set result
to @"FizzBuzz"
. We'll also have to alter the current leading if (i % 3 == 0 ) { ... }
statement into an else if
statement since it no longer leads the switch block:
for (NSUInteger i = 1; i <= 100; i++) {
NSString *result = @"";
if (i % 3 == 0 && i % 5 == 0) {
result = @"FizzBuzz";
}
else if (i % 3 == 0) { // becomes an 'else if' statement
result = @"Fizz";
}
else if (i % 5 == 0) {
result = @"Buzz";
}
else {
result = [NSString stringWithFormat:@"%lu", i];
}
NSLog(@"%@", result);
}
This should now print the correct sequence to FizzBuzz:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
7 — Now that we have a working (but not ideal) implementation of FizzBuzz, we can play around with the loop's parameters to get a different "slice" of the FizzBuzz sequence. While we could do this directly in the loop's conditional line, let's move the values into variables to follow good-practice guidelines of avoiding "magic numbers". Before the loop, declare two NSUInteger
variables called start
and limit
. Set them equal to 1
and 100
respectively and replace the integers in the for
loop's conditional line with these new variables.:
NSUInteger start = 1;
NSUInteger limit = 100;
for (NSUInteger i = start; i <= limit; i++) {
NSString *result = @"";
if (i % 3 == 0 && i % 5 == 0) {
result = @"FizzBuzz";
}
else if (i % 3 == 0) { // becomes an 'else if' statement
result = @"Fizz";
}
else if (i % 5 == 0) {
result = @"Buzz";
}
else {
result = [NSString stringWithFormat:@"%lu", i];
}
NSLog(@"%@", result);
}
This should still print the FizzBuzz sequence from 1
to 100
:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
8 — Now, play around with the values of start
and limit
. Try getting the slice of 100
to 130
:
NSUInteger start = 100;
NSUInteger limit = 130;
...
This should print:
Buzz
101
Fizz
103
104
FizzBuzz
106
107
Fizz
109
Buzz
Fizz
112
113
Fizz
Buzz
116
Fizz
118
119
FizzBuzz
121
122
Fizz
124
Buzz
Fizz
127
128
Fizz
Buzz
-
The FizzBuzz exercise is primarily about best practice and efficiency. Can you identify some of the problems with the implementation of FizzBuzz that we wrote? For starters, it repeats itself, both in the conditional checks, and in the instructions. Can you come up with a better logical structure that doesn't repeat itself?
-
Furthermore, while we did document the starting and ending points for the loop by saving the values into the
start
andlimit
variables, the remainder (%
) calculations are still written with "magic numbers". Document these values by creating new variables calledfizzIncrement
andbuzzIncrement
that are set to3
and5
respectively.