6
\$\begingroup\$

I saw this question: Is this FizzBuzz Swift-y? and I couldn't resist the temptation to attempt a Swift2 implementation:

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

Is this swift-y and clear enough? Can you suggest any improvement?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You could make it a function where you pass "Fizz", "Buzz" and the numbers as parameters to be more re-usable. \$\endgroup\$ Aug 28, 2015 at 16:01

3 Answers 3

4
\$\begingroup\$

Disclaimer: I don't know sqat about

It's clear and aesthetically pleasing.

But, I think in any language, this is a sign of abusing the switch construct:

case _ where ...
case _ where ...
case _ where ...
default:

That is, using a bunch of useless "case _ where" is a sign that probably should replace with natural and good old fashioned if-else-if-else.

Another thing, I see that you nicely aligned the : in all four lines. Sometimes that looks pretty. But such practice usually bites you back later when you need to modify the code. Later when adding one more case/if, instead of focusing on the new case/if alone, if it would place a new : out of order with the others, then you would be compelled to edit all the other lines too.

\$\endgroup\$
9
\$\begingroup\$

I would have started by looking over more than just the question in the linked question. You should have looked at the answers.

First of all, while the added where clause option in switch statements is a nice addition to the language, it doesn't make anything better here.

Moreover, we're failing on the single-responsibility-principle by not extracting out a method which takes an Int and returns a String and then simply looping over calls to this function.

So, the answer to this question is effectively going to be an a rewrite of the accepted answer of the linked question:

func fizzBuzzify(value: Int) -> String {
    switch (value % 3, value % 5) {
    case (0,0): return "FizzBuzz"
    case (0,_): return "Fizz"
    case (_,0): return "Buzz"
    default: return String(value)
    }
}

func fizzBuzz(startingValue: Int = 1, endingValue: Int = 100) {
    for i in startingValue...endingValue {
        print(fizzBuzzify(i))
    }
}

Then you get it all done in a single line:

fizzBuzz()
\$\endgroup\$
1
  • \$\begingroup\$ What about replacing the startingValue/endingValue pair with a single range: Range<Int> argument? It would make the fizzBuzz function as simple asrange.forEach(fizzBuzzify). \$\endgroup\$ Feb 3, 2016 at 14:12
0
\$\begingroup\$

I personally like nhgrif's answer. If you want to take it to the next level you could possibly define your FizzBuzz solution as a SequenceType (Swift 2.2) Sequence (Swift 3.0)

struct FizzBuzzSequence: Sequence {
  func makeIterator() -> AnyIterator<String> {
    var _first = 0
    func fizzBuzzify(value: Int) -> String {
        switch (value % 3, value % 5) {
        case (0,0): return "FizzBuzz"
        case (0,_): return "Fizz"
        case (_,0): return "Buzz"
        default: return String(value)
        }
    }    
    return AnyIterator<String> {
      _first += 1
      return fizzBuzzify(value: _first)
    }
  }
}

var fizzBuzzIterator = FizzBuzzSequence().lazy.makeIterator()
for _ in 0..<200 {
  if let val = fizzBuzzIterator.next(){
    print(val)
  }
}

Doing so would provide your FizzBuzz sequence with map, reduce and filter functionality on top of many other good stuff for free.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.