Skip to content

Instantly share code, notes, and snippets.

@Ogaday
Last active July 13, 2023 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ogaday/cd000a430bae9346dc694cc514c81c02 to your computer and use it in GitHub Desktop.
Save Ogaday/cd000a430bae9346dc694cc514c81c02 to your computer and use it in GitHub Desktop.
FizzBuzz implementations

FizzBuzz

The classic programming puzzle, tackled a few different ways.

Test and lint:

pip install -r requirements.txt
black --check .
flake8 *.py
mypy *.py
pytest

Example usage:

python3 -m naive 10
python3 -m strings 100
python3 -m cycles -h
import argparse
from collections.abc import Generator
from typing import Callable, List, Optional
class Cli:
"""A uniform interface for all FizzBuzz methods.
Examples
--------
>>> def fizzbuzz(n: int) -> Generator[str, None, None]:
... yield from range(1, n + 1)
>>> cli = Cli(func=fizzbuzz)
>>> cli(["10"])
1 2 3 4 5 6 7 8 9 10
"""
def __init__(self, func: Callable[[int], Generator[str, None, None]]):
"""Create a new CLI instance wrapping a Fizzbuzz implementation.
Parameters
----------
func
A generator function implementing FizzBuzz.
Attributes
----------
func:
A generator function implementating FizzBuzz.
parser:
The prepared argparse instance.
"""
self.func = func
self.parser = argparse.ArgumentParser(
description="A FizzBuzz program."
)
self.parser.add_argument(
"n", type=int, help="Run FizzBuzz up to n (inclusive)."
)
def __call__(self, args: Optional[List[str]] = None):
"""Call the CLI.
Outputs each element in the FizzBuzz sequence on a newline.
Parameters
----------
args
Optional list of arguments to override ``sys.argv`` (for testing
purposes, for instance).
"""
parsed = self.parser.parse_args(args=args)
for i in self.func(parsed.n):
print(i)
from collections.abc import Generator
from itertools import cycle
def fizzbuzz(n: int) -> Generator[str, None, None]:
"""
An FizzBuzz implementation which avoids division.
Uses cycles to produce the output without having to check the modulus.
Parameters
----------
n : int
Run the FizzBuzz program between 1 and n (inclusive).
Examples
--------
>>> list(fizzbuzz(20))
['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11',
'Fizz', '13', '14', 'FizzBuzz', '16', '17', 'Fizz', '19', 'Buzz']
"""
fizzes = cycle(["", "", "Fizz"])
buzzes = cycle(["", "", "", "", "Buzz"])
for f, b, i in zip(fizzes, buzzes, range(1, n + 1)):
yield f + b or str(i)
if __name__ == "__main__":
from cli import Cli
cli = Cli(fizzbuzz)
cli()
from collections.abc import Generator
from itertools import cycle
from typing import Tuple
class FizzBuzz:
"""
A general purpose FizzBuzz generator.
Examples
--------
First, a simple a example where every fourth integer is replace with
"Boar":
>>> fizzbuzz = FizzBuzz(("Boar", 4))
>>> list(fizzbuzz(10))
['1', '2', '3', 'Boar', '5', '6', '7', 'Boar', '9', '10']
Then the classic FizzBuzz:
>>> fizzbuzz = FizzBuzz(("Fizz", 3), ("Buzz", 5))
>>> list(fizzbuzz(20))
['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11',
'Fizz', '13', '14', 'FizzBuzz', '16', '17', 'Fizz', '19', 'Buzz']
"""
def __init__(self, *args: Tuple[str, int]):
"""Create a new FizzBuzz generator.
Parameters
----------
*args
Pairs of word/integer to replace. See example.
"""
self.words = args
def __call__(self, n: int) -> Generator[str, None, None]:
"""Run FizzBuzz.
Parameters
----------
n : int
Run the FizzBuzz program between 1 and n (inclusive).
"""
cycles = [
cycle([""] * (divisor - 1) + [word])
for word, divisor in self.words
]
for *step, i in zip(*cycles, range(1, n + 1)):
yield "".join(step) or str(i)
fizzbuzz = FizzBuzz(("Fizz", 3), ("Buzz", 5))
if __name__ == "__main__":
from cli import Cli
cli = Cli(fizzbuzz)
cli()
from collections.abc import Generator
def fizzbuzz(n: int) -> Generator[str, None, None]:
"""
A naive FizzBuzz implementation.
Uses if/else conditions to decide what to output at each stage.
Parameters
----------
n : int
Run the FizzBuzz program between 1 and n (inclusive).
Examples
--------
>>> list(fizzbuzz(20))
['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11',
'Fizz', '13', '14', 'FizzBuzz', '16', '17', 'Fizz', '19', 'Buzz']
"""
for i in range(1, n + 1):
if i % 15 == 0:
yield "FizzBuzz"
elif i % 5 == 0:
yield "Buzz"
elif i % 3 == 0:
yield "Fizz"
else:
yield str(i)
if __name__ == "__main__":
from cli import Cli
cli = Cli(fizzbuzz)
cli()
[tool.black]
line-length = 79
target-version = ['py310']
[tool.pytest.ini_options]
addopts = "--doctest-modules"
doctest_optionflags = "NORMALIZE_WHITESPACE"
black
flake8
mypy
pytest
from collections.abc import Generator
def fizzbuzz(n: int) -> Generator[str, None, None]:
"""
A one-liner FizzBuzz implementation.
Builds an output string based on conditionals.
Parameters
----------
n : int
Run the FizzBuzz program between 1 and n (inclusive).
Examples
--------
>>> list(fizzbuzz(20))
['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11',
'Fizz', '13', '14', 'FizzBuzz', '16', '17', 'Fizz', '19', 'Buzz']
"""
for i in range(1, n + 1):
yield "Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or str(i)
if __name__ == "__main__":
from cli import Cli
cli = Cli(fizzbuzz)
cli()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment