loading...

An Examination of Fizzbuzz

zeeter profile image Daniel Smith ・2 min read

Table of Contents

Introduction

The fizz buzz problem is a type of programming challenge to show if a person knows how to program.
Essentially the challenge goes like this, you must create a program that will print fizz every multiple of 3, buzz every multiple of 5,
and fizz buzz on multiples of both fizz and buzz.
EDIT I forgot to mention that if n is neither a multiple of 3 or 5 it just prints the number.

These are my attempts on this challenge.
This article is ongoing as I am given new things to try.

First Attempt

for n in range(1,101):
    cond1 = n % 3 == 0
    cond2 = n % 5 == 0

    if cond1 and not cond2:
        print("fizz")
    elif cond2 and not cond1:
        print("buzz")
    elif cond1 and cond2:
        print("fizz buzz")
    else:
        print(n)

So the first try works as needed. However this method does not readly support changes.
I did however make the choice based on conditions, however adding in additional conditions would be a pain.
Also the code executes the moment that you run it, which is not a very good practice in the python land.

Second Attempt

import sys
import argparse


def if_multiple(n, multiple, string):
    if n % multiple == 0:
        return string
    else:
        return ''

def n_if_empty(output, n):
    if output == '':
        return str(n)
    else:
        return ''

def fizzbuzz(start=1,
          stop=101):

    for n in range(start,stop):

        output = ''
        output += if_multiple(n,3,"fizz")
        output += if_multiple(n,5,"buzz")
        output += n_if_empty(output, n)
        print(output)

def main():
    parser = argparse.ArgumentParser(description="A program that plays fizzbuzz.")
    parser.add_argument('start', type=int, help="The number to count from (Default 1)", default=1)
    parser.add_argument('stop', type=int, help="The number to count to (Default: 100)", default=100)

    args = parser.parse_args()

    fizzbuzz(args.start, (args.stop + 1))

    return None




if __name__ == '__main__':
    main()
    sys.exit()

The second version is better in my opinion. It no longer relies on messy else if logic, and is instead although I did not run this code through autopep8 so it is not necessarily pythonic. However this version is rather neat. You can import the fizzbuzz function if need be, and you can also import the other functions. Adding in a new bit of logic is as simple as adding in a new line. And changing the string to print is as simple as changing a variable.

EDIT I removed the bash calls from the code blocks, I still haven't quite figured out the org markdown export yet. This code should run without any syntax errors.

Posted on Aug 1 '17 by:

zeeter profile

Daniel Smith

@zeeter

Howdy howdy, I'm Daniel mad scientist extraordinaire. I have been programming in python since 2012, and other things as I please.

Discussion

markdown guide
 

You've created a nice, maintainable FizzBuzz Python implementation. What I find really, really interesting is that, in your description of your requirements, you left out "otherwise, print the number." This is what most FizzBuzz interviewees leave out of their implementation. You nailed it in your implementation, but missed it in your plain-English description of the problem.

I'm not trying to "rip up" your post - I think it's instructive of how easy it is to miss a detail in requirements. We always need to be on the lookout for details we missed. Our customers may not care, but the computers that interpret our code certainly do! :)

(And, yes - there are way better implementations than the typical "if 0 == x % 15 then 'fizzbuzz' elseif 0 == x % 5 then 'buzz' elseif 0 == x % 3 then 'fizz' else x" that the interviewer typically sees.)

Finally, a side note - people like to rip on this as a basic-level test, but from a functional perspective, it's a mapping problem. (1 = '1', 2 = '2', 3 = 'fizz', 4 = '4', 5 = 'buzz', etc.) Your if_multiple and n_if_empty functions show that you can abstract a problem into reusable parts. It may appear to be over-engineered to some (and probably would be for an interview), but it shows that you understand the steps involved. Nice post!

 

Thank you for the feedback.
I am a little confused by your statement, that I left out the "otherwise print the number" statement. I double checked my code and the output was the exact same as both my test output and my first attempts code. Was it in my introduction that I missed the statement or the code itself? Either way its a pretty easy fix.

 

Oh heck I'm sorry, I misread your comment.
Thank you for pointing that out, I'll update the introduction.

 

Hmm, I actually like the first one better. I feel like the second one should be better from a modularity standpoint, but I find the first one much more readable and clear as to what it does (if the variables were renamed to something like div_3 and div_5). Perhaps making a nice mix of the two would be good!

I think the biggest flaw in the second example is the output variable. Whenever I see str += otherStr inside of a small for loop, I think that it is building up a string to become longer and longer as a for loop persists (as if you were going to print all of them at once). It's just a common pattern, took me a second to realize that wasn't what you were doing.

One last thing - I think that perhaps because fizzbuzz is a problem based on conditions, maybe using conditional operators such as if and elif is ok, and maybe a bit more readable.

 

Still my favourite implementation, because it is completely declarative:

createRule n s = cycle $ replicate (n-1) "" ++ [s]
fizzes = createRule 3 "Fizz"
buzzes = createRule 5 "Buzz"
fizzBuzzes = zipWith (++) fizzes buzzes
numbers = fmap show [1..]
choose a b = if a == "" then b else a
result = zipWith choose fizzBuzzes numbers

main = mapM_ putStrLn $ take 100 result
 

nice one - here is basically the same (I did not care about the prompt) in Haskell:

module FizzBuzz where

import Data.Function ((&))
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))


fizzBuzz :: Int -> Int -> [String]
fizzBuzz from to = fizzBuzzer <$> [from .. to]

----------------------------------------------------------------------

fizzBuzzer :: Int -> String
fizzBuzzer n = Nothing
  <> ifMultiple 3 "Fizz" n
  <> ifMultiple 5 "Buzz" n
  &  nIfEmpty n


ifMultiple :: Int -> String -> Int -> Maybe String
ifMultiple d out n
  | n `mod` d == 0 = Just out
  | otherwise      = Nothing


nIfEmpty :: Int -> Maybe String -> String
nIfEmpty n = fromMaybe (show n)

isn't it nice how that just translates


PS: the n there should probably be refactored into a Reader-Monad :P

 

Problems like FizzBuzz serve another purpose besides screening for programming proficiency, as I think you've discovered in your second example. They also provide a convenient way to explore different programming paradigms and styles of coding. To that extent, I find your second example very "Pythonic", even if it's not exactly how I'd personally prefer to do it. (Unsurprisingly, while I do code quite a bit in Python, it's almost never the language I reach for if I have a choice.)

If you (or anyone else) are interested in more of these kinds of problems:

Finally, there's also the entire Rosetta Code wiki that covers a large number of algorithms, from simple to complex, in a wide variety of different languages.

 

Well that's a way to over-engineer a simple programming test.

 

I disagree. I'd much rather debug code from a person who writes code in the second way than the first. For me, at least, posts like this are great little learning tools to help me understand the fundamentals better...

 

I second this, this shows the fundamentals and importance of clean code. Making it clean makes it readable for others.

 

I'll admit, I went a bit overboard with the argparser. And I could have named the functions better. What I was looking to do with the second version was create a version that could relatively easily be updated for more complicated versions of the problem. For example if the interviewer wanted me to revise it so that it printed fizz on every multiple of 7.

If you have any suggestions on how I could simplify my code, I would be more than happy to potentially incorporate them into fizzbuzz3.

 

This comment was not constructive. Please consider a more helpful/thoughtful way to provide feedback in future comments.

 

I consider the second one to be overly abstracted. The first one is far simpler. It implements the requirements fully without any overhead. Planning for being adaptable is part of YAGNI syndrome. Things are easy to refactor when new requirements are added. Adding complexity in advance is counter-productive.

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

I feel it is over engineered, though i like such unique solutions practically this should not hit the production.