DEV Community

D Smith
D Smith

Posted on

An Examination of Fizzbuzz

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)

Enter fullscreen mode Exit fullscreen mode

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()

Enter fullscreen mode Exit fullscreen mode

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.

Top comments (15)

Collapse
 
danieljsummers profile image
Daniel J. Summers

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!

Collapse
 
zeeter profile image
D Smith

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.

Collapse
 
zeeter profile image
D Smith

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

Thread Thread
 
danieljsummers profile image
Daniel J. Summers

Yeah, you got it. :)

Collapse
 
dean profile image
dean • Edited

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.

Collapse
 
jvanbruegge profile image
Jan van Brügge • Edited

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
Collapse
 
carstenk_dev profile image
Carsten • Edited

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

Collapse
 
gyorgygutai profile image
gyorgygutai

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

Collapse
 
jeffpollet profile image
Solidarity&Resist

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...

Collapse
 
woahitsjck profile image
Justin Chew

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

Collapse
 
ben profile image
Ben Halpern

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

Collapse
 
zeeter profile image
D Smith

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.

Collapse
 
jballanc profile image
Joshua Ballanco

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.

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

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.

Collapse
 
metacritical profile image
Pankaj Doharey

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