12

I'm doing this problem set "FizzBuzz", and my switch statement is giving me some problems, here's my code:

func fizzBuzz(n: Int) -> String {   
    switch n {
    case n % 3 == 0: print("Fizz")
    case n % 5 == 0: print("Buzz")
    case n % 15 == 0:print("FizzBuzz")
    }
    return "\(n)"
}

If you could provide me with pointers / hints, instead of giving me the correct code, that would be swell :D I'd prefer solving it myself, but a few hints could get me out of this hole.

pkamb
  • 33,281
  • 23
  • 160
  • 191
user3724487
  • 123
  • 1
  • 6
  • 3
    First hint: `where` clause – vadian Nov 28 '15 at 19:43
  • 1
    Other hint: maybe you want your method to `return` the string for each case instead of just printing them and returning n... experiment with this. Then you could use the result of the method to print, instead of printing in the method. – Eric Aya Nov 28 '15 at 19:48
  • Related: http://stackoverflow.com/questions/25279000/switch-statement-in-swift (but unfortunately it contains a full solution:) – Martin R Nov 28 '15 at 19:56
  • 2
    Another hint: The cases are evaluated in order from top to bottom, so think about where you want the "FizzBuzz" case to be so that it gets hit. – vacawama Nov 28 '15 at 21:07

4 Answers4

17

You can use case let where and check if both match before checking them individually:

func fizzBuzz(n: Int) -> String {
    let result: String
    switch n {
    case let n where n.isMultiple(of: 3) && n.isMultiple(of: 5):
        result = "FizzBuzz"
    case let n where n.isMultiple(of: 3):
        result = "Fizz"
    case let n where n.isMultiple(of: 5):
        result = "Buzz"
    default:
        result = "none"
    }
    print("n:", n, "result:", result)
    return result
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    I had a similar situation where I wanted to do something different based on the (generic) Element Type of an Array and this was the only thing that worked for me. Thank you! – SilentDirge Jun 23 '17 at 16:51
12

Just two things wrong:

(1) Your cases are boolean expressions, so you want to compare them against true, not n;

(2) You need a default case. So:

func fizzBuzz(n: Int) -> String {
    switch true {
    case n % 3 == 0: print("Fizz")
    case n % 5 == 0: print("Buzz")
    case n % 15 == 0: print("FizzBuzz")
    default: print("Shoot")
    }
    return "\(n)"
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    This is interesting, `switch true` rather than `switch n` to get around the ugly/useless boilerplate needed otherwise: `case let n where n % 3 == 0:`. – pkamb Nov 10 '17 at 23:54
  • The case order needs to be changed. Calling this with 15 gives "Fizz", not "FizzBuzz". – HangarRash Mar 29 '23 at 04:10
2

I know its little late for this answer. I am updating the answer of @Leo Dabus with an another approach which is written and tested on Xcode 7.3.1 and Swift 2.2.

func fizzBuzz(n: Int) -> String {
 switch n {
  case _ where n % 3 == 0:
    print("Fizz")
  case _ where n % 5 == 0:
    print("Buzz")
  case _ where n % 15 == 0:
    print("FizzBuzz")
  default:
    print("none")
 }
 return "\(n)"
}

Thanks, Hope this helped.

onCompletion
  • 6,500
  • 4
  • 28
  • 37
2

A bit late, but just to add to the various answers. I believe the elegant solution to use now is this:

func fizzBuzz(n: Int) {
    switch (n%3==0, n%5==0) {
    case (true, false):
        print("Fizz")
    case (false, true):
        print("Buzz")
    case (true, true):
        print("FizzBuzz")
    default:
        print(n)
    }
}

Swift can switch on tuples (sorta structs, but constructed on the fly without a definition somewhere else in the code). Then in the case labels you can check for multiple values at once, which is ideal for FizzBuzz!

To break it down a bit, this part

(n%3==0, n%5==0)

generates a tuple with two boolean values. Then a case label like this

case (true, true)
    print("FizzBuzz")

checks if both these values (essentially n%3==0 and n%5==0) are true and prints "FizzBuzz"

Doing it like this makes it very easily expandable. You can add a third definition to the switch argument and a third true/false to your cases and your FizzBuzz can become a FizzBuzzJazz. You can also name the values in the tuple if you want by simply adding labels like

switch (fizz: n%3==0, buzz: n%5==0, jazz: n%7==0) {
case (fizz: true, buzz: false, jazz: true)
    print("FizzJazz")
}

making the code more readable in some cases.

kevin
  • 442
  • 3
  • 13