Switch statement in Swift
Asked Answered
W

8

49

I'm learning syntax of Swift and wonder, why the following code isn't working as I expect it to:

for i in 1...100{

    switch (i){
    case 1:
        Int(i%3) == 0
        println("Fizz")
    case 2:
        Int(i%5) == 0
        println("Buzz")
    default:
        println("\(i)")
    }  
}

I want to print Fizz every time number is divisible by 3 (3, 6, 9, 12, etc) and print Buzz every time it's divisible by 5. What piece of the puzzle is missing?

Note: I did solve it using the following:

for ( var i = 0; i < 101; i++){

    if (Int(i%3) == 0){
        println("Fizz")
    }   else if (Int(i%5) == 0){
        println("Buzz")
    }   else {
        println("\(i)")
    }   
}

I want to know how to solve this using Switch. Thank you.

Whimwham answered 13/8, 2014 at 5:57 Comment(5)
did you read switch statement in Swift guide?Cossack
for this If- Else would be much better then SwitchPane
No Bryan i haven't read reference guide, thank you for link.Whimwham
You have a logical error in there: For any number that is divisible by 3 AND 5, you are only printing "Fizz", instead of "Fizz Buzz".Valora
Im not familiar with game rules, i try to understand syntax :)Whimwham
C
112

The usual rules for the FizzBuzz game are to replace every multiple of 3 by "Fizz", every multiple of 5 by "Buzz", and every multiple of both 3 and 5 by "FizzBuzz".

This can be done with a switch statement on the tuple (i % 3, i % 5). Note that _ means "any value":

for i in 1 ... 100 {
    switch (i % 3, i % 5) {
    case (0, 0):
        print("FizzBuzz")
    case (0, _):
        print("Fizz")
    case (_, 0):
        print("Buzz")
    default:
        print(i)
    }
}
Cacophonous answered 13/8, 2014 at 7:12 Comment(4)
This, to me, looks like the right answer to the question that should have been asked :)Apollus
Thats a bit hard to understand, but i think this is correct answer, thank you Martin.Whimwham
Beautiful answer :) That's when you use the specific benefits of a language to solve a problem.Tacye
@Dx agreed. I love how you can switch on multiple values at once. Python doesn't even have a switch statement.Vampirism
C
25

Switch statements in Swift support value bindings.
This allows you to assign a value that matches a certain condition (evaluated via the where clause) to a temporary variable (x & y here):

for i in 1...100 {
    switch (i){
    case let x where x%3 == 0:
        println("Fizz")
    case let y where y%5 == 0:
        println("Buzz")
    default:
        println("\(i)")
    }
}

You could also use the assigned temp value in the case body.

Update:
Matt Gibson points out in the comments, that you can omit the assignment to a temp var if you are not going to use it in the case body.
So a more concise version of the above code would be:

for i in 1...100 {
    switch (i){
    case _ where i%3 == 0:
        println("Fizz")
    case _ where i%5 == 0:
        println("Buzz")
    default:
        println("\(i)")
    }
}

Side note: Your 2 code samples are slightly different (the first one uses the range 0-100 as input, while the second one operates on 1-100). My sample is based on your first code snippet.

Comminate answered 13/8, 2014 at 6:42 Comment(2)
You don't need the "let x", "let y", seeing as you're not really using the values, you can do, e.g. case _ where i%3 == 0:Apollus
Thank you very much weichsel for clarifying this for me.Whimwham
C
20

This is a more general answer for people who come here just wanting to know how to use the switch statement in Swift.

General usage

switch someValue {
case valueOne:
    // executable code
case valueTwo:
    // executable code
default:
    // executable code
}

Example

let someValue = "horse"

switch someValue {
case "horse":
    print("eats grass")
case "wolf":
    print("eats meat")
default:
    print("no match")
}

Notes:

  • No break statement is necessary. It is the default behavior. Swift switch cases do not "fall through". If you want them to fall through to the code in the next case, you must explicitly use the fallthrough keyword.
  • Every case must include executable code. If you want to ignore a case, you can add a single break statement.
  • The cases must be exhaustive. That is, they must cover every possibly value. If it is not feasible to include enough case statements, a default statement can be included last to catch any other values.

The Swift switch statement is very flexible. The following sections include some other ways of using it.

Matching multiple values

You can match multiple values in a single case if you use separate the values with commas. This is called a compound case.

let someValue = "e"

switch someValue {
case "a", "b", "c":
    // executable code
case "d", "e":
    // executable code
default:
    // executable code
}

You can also match whole intervals.

let someValue = 4

switch someValue {
case 0..<10:
    // executable code
case 10...100:
    // executable code
default:
    // executable code
}

You can even use tuples. This example is adapted from the documentation.

let aPoint = (1, 1)

switch aPoint {
case (0, 0):
    // only catches an exact match for first and second
case (_, 0):
    // any first, exact second
case (-2...2, -2...2):
    // range for first and second
default:
    // catches anything else
}

Value Bindings

Sometimes you might want to create a temporary constant or variable from the switch value. You can do this right after the case statement. Anywhere that a value binding is used, it will match any value. This is similar to using _ in the tuple example above. The following two examples are modified from the documentation.

let anotherPoint = (2, 0)

switch anotherPoint {
case (let x, 0):
    // can use x here
case (0, let y):
    // can use y here
case let (x, y):
    // can use x or y here, matches anything so no "default" case is necessary
}

You can further refine the matching by using the where keyword.

let yetAnotherPoint = (1, -1)

switch yetAnotherPoint {
case let (x, y) where x == y:
    // executable code
case let (x, y) where x == -y:
    // executable code
case let (x, y):
    // executable code
}

Further study

  • This answer was meant to be a quick reference. Please read the full documentation for more. It isn't difficult to understand.
Cartesian answered 7/12, 2017 at 5:39 Comment(0)
S
4

This is how it can be done

var i = 0

switch i  {

case i where i % 5 == 0 && i % 3 == 0: print(" Fizz Buzz")
case i where i % 3 == 0 : print("Fizz")
case i where i % 5 == 0 : print("Buzz")
default: print(i)

}
Scratch answered 26/4, 2016 at 17:25 Comment(0)
C
1

The industry standard behaviour of switch can lead to bugs similar to "Go to Fail".

Basically the code doesn't always do exactly what it looks like the code will do when reading over it, which leads to code auditors skipping over critical bugs.

To counter that, Apple has decided switch statements should not work the same in Swift as the industry standard. In particular:

  • There is an automatic break at the end of every case. It's impossible for more than one case statement to execute.
  • If it's theoretically possible for one of the case statements to be missed, then the code will not compile at all. In swift one of the case statements will always execute, no matter what value is provided. If you provide an enum, every enum value must be handled. If a new value is added to an existing enum the code won't compile until new case statements are added. If you provide a 32 bit integer, you must handle every possible value of a 32 bit int.
Chemulpo answered 13/8, 2014 at 6:11 Comment(4)
Abhi, that interesting, you mean i can't use such enumerating like i did with for-in with "switch" statement? it only suppose to handle "small" number of decent events?Whimwham
Note that you can avoid the automatic break by using the fallthrough keyword, and that for a 32-bit integer, it's fine to use default to handle every case that's not specifically handled.Apollus
@MattGibson but that is an automatic fallthrough and does not do the test on the next case - so not oif use in then OP's caseVincentvincenta
@Mark My comment (nearly three years ago! Wow!) was merely addressing "It's impossible for more than one case statement to execute" in this answer, not the OP.Apollus
U
1

Here are the two ways I use switch statement for this kind of problems .

1>> Using where keyword

func printNumberType(number : Int){
    
    switch number {
    case number where number % 3 == 0 && number % 5 == 0 :
        print("foo bar")
    case number where number % 3 == 0 :
        print("foo")
    case number where number % 5 == 0 :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}

2>> Using values combination

func printNumberByMultipleValues(number : Int){
    
    let combination = (number % 3,number % 5)
    
    switch combination {
    case (0,0):
        print("foo bar")
    case (0,_) :
        print("foo")
    case (_,0) :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}

Here is closer example for multiple value type .

var printNumberByMultipleValues : (Int)->() = { number in
    
    let combination = (number % 3,number % 5)
    
    switch combination {
    case (0,0):
        print("foo bar")
    case (0,_) :
        print("foo")
    case (_,0) :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}
Ut answered 25/8, 2020 at 6:25 Comment(0)
H
-1

Use this code. Your logic is wrong. Your Switch Statement does not find the case accept 1 and 2

class TEST1{
func print() -> Void{
    var i = 0
    for i in 1...100{
        if Int(i%3) == 0 {
            println("Fizz")
        }
        else if Int(i%5) == 0{
            println("Buzz")
        }
        else {
            println("\(i)")
        }   
    }
}
}
var x = TEST1()
x.print()
Holinshed answered 13/8, 2014 at 6:24 Comment(2)
Do you read my entire post? Please read again, i already did this using for-in statement with "if-else".Whimwham
Bhaskar i asked how to solve this task using switch statement. Please look more carefully of what people asking for. Your answer does not provide any solution or clue, how to solve my issue. Thank you.Whimwham
R
-1

Was playing around with this and came up with two solutions that read a bit different. Personal I like the switch statement more and use .isMultiple(of: 3) on my index number.

Option 1 | Switch

for i in 1...100 {
    switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) {
    case (true, true):
        print("\(i) | FizzBuzz")
    case (true, false):
        print("\(i) | Fizz")
    case (false, true):
        print("\(i) | Buzz")
    default:
        print(i)
    }
}

Option 2 | If statements

for i in 1...100 {
    if i.isMultiple(of: 3) && i.isMultiple(of: 5) {
        print("\(i) | FizzBuzz")
    } else if i.isMultiple(of: 3) {
        print("\(i) | Fizz")
    } else if i.isMultiple(of: 5) {
        print("\(i) | Buzz")
    } else {
        print(i)
    }
}
Ruinous answered 13/8, 2023 at 23:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.