DEV Community

the_savage
the_savage

Posted on

FizzBuzz using streams in Python

So this evening I was fooling around with the concept of using monoids to play around with streams. The idea here is to break a relatively abstract concept into something that a noOb can follow along, and it hit me; why not demo all this stuff using the classic Fizz-buzz algorithm.

Generally, for a fizz-buzz problem, you print out "Fizz" if a number is divisible by 3; and alternatively, you print "Buzz" if it's divisible by 5. Needless to say, you print "FizzBuzz" if it's divisible by both 3 and 5. Now a simple implementation in python would be something like:

def fizz_buzz(n):
    for i in range(1, n+1):
        if (i % 3 == 0 and i % 5 == 0):
            print("{}: FizzBuzz".format(i))
            continue
        if (i % 3 == 0):
            print("{}: Fizz".format(i))
            continue
        if (i % 5 == 0):
            print("{}: Buzz".format(i))


fizz_buzz(100)        

Well for one, I don't like that the above function has side-effects. How can we refactor this to use streams? First of all, let's clear up what a stream is. A stream is a sequence of objects which can be accessed in sequential order. Where do monoids come in? Well a monoid allows us to combine things. A monoid has a single associative "structure"(in our case this is the "append" operation that zip provides). In this case, when we have a stream, we can combine several monoids from a stream using zip. Let's look at it in Python:

from itertools import cycle


def fizz_buzz(n):
    """Return an iter list with fizz-buzz"""
    fizz_buzz = zip(cycle(['', '', '', '', 'Fizz']),
                    cycle(['', '', 'Buzz']),
                    [i for i in range(1, n+1)])
    return filter(lambda x: (x[0] != '' or x[1] != ''),
                  fizz_buzz)

for i in fizz_buzz(100):
    print("{}: {}{}".format(i[2], i[0], i[1]))

From the above snippet, we first generate a stream of "Fizzes" and "Buzzes", then we combine them with zip after which we filter any element from the stream that has no "Fizz" or "Buzz". Python's loose typing makes it easy for us to combine and morph things. Notice that the fizz_buzz function returns a generator which has it's own merits.

If you want to functional programming tips, I post interesting reads on a google groups I started a while back here https://groups.google.com/forum/#!forum/nairobi-functional-programming-community

Top comments (1)

Collapse
 
weeb profile image
Patrik Kiss

Good to see a fellow man of culture on DEV.