Here's my approach to an extensible version of the FizzBuzz challenge in Swift (so one can add more numbers to be checked against other than just3 and5).
I initially tried using dictionaries but since they don't necessarily preserve the order of elements it could lead toBuzzFizz return values.
I personally think that, while the program does work as expected, it isn't clear how it works. I mean, it's not as readable as I'd like it to be for doing such a simple task.
How can I improve it?
func fizzBuzz (n: Int, responsesByMultiples: [(Int, String)] = [(3, "Fizz"), (5, "Buzz")]) -> String { var result: String = "" for key in responsesByMultiples { let (multiple, response) = key, isMultiple: Bool = (n % multiple) == 0 if isMultiple { result += response } } return result == "" ? String(n) : result}for i in 1...100 { print(fizzBuzz(n: i))}1 Answer1
🔆 Bright side
Your code gives the correct output and delivers on the premise of extensibility.
📝 Suggestions
Here are some suggestions:
The name
keyis a name that doesn't tell a lot about the nature of the tuple. If you feel that it is appropriate, that would conflict withresponsesByMultiples. Then It would have made more sense for the latter to be namedkeys. Personally, I'd prefer to callresponsesorrules.Theserules expressed by a tuple without labels is a little bit confusing. Better use a struct, or just add labels.
You can easily decompose a tuple this way:
for (multiple, response) in responsesByMultiples { ...}Calling the first element
multipleis a little bit too optimistic (or pessimistic depending on the way you to see things), it presumes that there is a high probability thatnis actually a multiple ofmultiple. It would make more sense to me to name the first element of the tuplesdividsor.nis a bit too generic, usedividendinstead.You don't have to specify the type in
isMultiple: Bool, type inference can do the job for you. Generally speaking, specifying the type can help in reducing the compile times, but in this case, it wouldn't make a difference.Instead of using
(n % multiple) == 0, there is a nicesyntax in Swift 5 :n.isMultiple(of: multiple)(this syntax exacerbates the problem mentioned in 4.)
To check that a String is empty, it is more efficient to check the
.isEmptyproperty.Here is a benchmark that confirms it:import Foundationlet array = (0..<1_000_000).map { _ in Double.random(in: 0..<1) < 0.8 ? "" : String("Hello".shuffled())}do { let start = Date() let result = array.filter { $0 == "" } let end = Date() print(result.count, end.timeIntervalSince(start))}do { let start = Date() let result = array.filter { $0.isEmpty } let end = Date() print(result.count, end.timeIntervalSince(start))}The execution times are respectively
44msand34ms.
💔 Putting it all together ❤️
Here a version of your code that takes the previous points into account :
func fizzBuzz ( number dividend: Int, rules: [(Int, String)] = [(3, "Fizz"), (5, "Buzz")] ) -> String { var result: String = "" for (divider, response) in rules where dividend.isMultiple(of: divider) { result += response } return result.isEmpty ? String(dividend) : result}🧐 Further reading
You can find many implementations of this classic question on Code Review.Here is a quite informative one.
- 1\$\begingroup\$Damn that is a very well formatted answer! I agree with every point on the list, except maybe #6 because I personally like using explicit typing. Thanks!\$\endgroup\$Tiago Marinho– Tiago Marinho2019-08-03 00:38:57 +00:00CommentedAug 3, 2019 at 0:38
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

