FizzBuzz the Functional Way

One of the most popular interview questions to weed out the good candidates from those that can’t code at all is the "FizzBuzz" problem.  It’s a simple programming exercise:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".

Seems pretty simple.  Anyone worth their salt should be able to crank out a solution in a couple minutes.  The standard way of solving this problem (in C#) would go something like:

            for (int i = 0; i < 100; i++)
            {
                if (i % 3 == 0 && i % 5 == 0)
                    Print(i, "FizzBuzz");
                else if (i % 3 == 0)
                    Print(i, "Fizz");
                else if (i % 5 == 0)
                    Print(i, "Buzz");
                else
                    Print(i, "");
            }

Just for fun I wanted to approach this from a functional perspective.  Essentially what we have here is a list from 0 to 99 at the beginning of the "pipeline" that must be passed through a number of filters.  Each filter must be applied to each element in the pipeline in turn and be given the chance to perform an action (i.e. print out the number and a phrase to the console).

The initial list of integers is easy enough:

Enumerable.Range(0, 100)

This returns an IEnumerable<int>.  I came up with two similar approaches at this point.  I also made a simple helper method to print out a number and a phrase (if any):

        private static void Print(int i, string message)
        {
            Console.WriteLine("{0}: {1}", i, message);
        }

Solution 1

For this solution, I recognized that the action of writing something to the console depends on a certain condition, so it makes sense to group these together into a class, like:

   public class ConditionalAction
    {
        public ConditionalAction(Predicate condition, Action action)
        {
            this.Condition = condition;
            this.Action = action;
        }

        public Predicate Condition { get; private set; }
        public Action Action { get; private set; }
    }

Now, I just needed a way to execute any number of ConditionalActions that I create in such a way that they are executed in order until one of the conditions is true.  This kind of operation kinda reminded me of a tee in a pipe, so I named this extension method Tee:

    public static class ExtensionMethods1
    {
        public static void Tee(this IEnumerable source, params ConditionalAction[] actions)
        {
            foreach (T item in source)
            {
                foreach (ConditionalAction action in actions)
                {
                    if (action.Condition(item))
                    {
                        action.Action(item);
                        break;
                    }
                }
            }
        }
    }

This extension method can be applied to any enumerable source and take any number of ConditionalActions as parameters (notice the "params" keyword).  Then, for each item in the source list, it applies each ConditionalAction by first testing to make sure that the ConditionalAction's Condition predicate (any method that takes one input argument of type T and returns a boolean) returns true.  If it does, then the ConditionalAction's Action predicate (any method that takes one input argument of type T) is executed.

Taking advantage of the code so far reduces the FizzBuzz problem to the following form:

            Enumerable.Range(0, 100)
                .Tee(
                new ConditionalAction(
                    i => i % 3 == 0 && i % 5 == 0, i => Print(i, "FizzBuzz")),
                new ConditionalAction(
                    i => i % 3 == 0, i => Print(i, "Fizz")),
                new ConditionalAction(
                    i => i % 5 == 0, i => Print(i, "Buzz")),
                new ConditionalAction(
                    i => true, i => Print(i, ""))
                );

I guess that's not too bad.  It's an interesting construct to be able to hang as many ConditionalActions off of the Tee method as you need.  It's still not very elegant and makes use of the "break" keyword to hardcode the execution of at-most one ConditionalAction into the extension method.

Solution 2

I wanted to eliminate the requirement for the "break" keyword in the Tee method, sensing that if I had an enumerable list of ConditionalActions I could just use the First() (build-in) extension method to accomplish this.

The FizzBuzz problem can then be looked at as: Take the list of integers from 0 to 99, and for each one apply all ConditionalActions in the list.  For the first one satisfying the Condition, do the Action."  Approaching from this direction, we get:

            ConditionalAction[] fizzbuzz = new ConditionalAction[]
            {
                new ConditionalAction(i => i % 3 == 0 && i % 5 == 0, i => Print(i, "FizzBuzz")),
                new ConditionalAction(i => i % 3 == 0, i => Print(i, "Fizz")),
                new ConditionalAction(i => i % 5 == 0, i => Print(i, "Buzz")),
                new ConditionalAction(i => true, i => Print(i,""))
            };
            Enumerable.Range(0, 100).ForEach(i => fizzbuzz.Where(item => item.Condition(i)).First().Action(i));

where the ForEach extension method is just like the one I talked about before. (Seriously, how could the LINQ designers have missed this?)

Wow, that's pretty succinct.  I like that alot.  Once we set up the array of ConditionalActions, executing them is only 1 line of code.  Nice.  We start with the range from 0 to 99, then for each element we find all fizzbuzz ConditionalActions that have their Condition satisfied for the current integer, only take the first one, and then apply the corresponding Action using the current integer.  Cool!

The code isn't shorter and it definitely was more work, but I just wanted to illustrate some of the cool new language features of C# 3.0.  I don't know what it is, but I keep finding these generics, anonymous methods, and lambda expressions immensely fascinating.

I suppose if you wanted to take it a step further, you could also get rid of the ConditionalAction class and go with an anonymous type as well.  Here's the same approach but using an anonymous type (notice the "var" keyword):

            var fizzbuzz = new[]
            {
                new {
                    Condition = new Predicate(i => i % 3 == 0 && i % 5 == 0),
                    Action = new Action(i => Print(i, "FizzBuzz"))
                },
                new {
                    Condition = new Predicate(i =>i % 3 == 0),
                    Action = new Action(i => Print(i, "Fizz"))
                },
                new {
                    Condition = new Predicate(i => i % 5 == 0),
                    Action = new Action(i => Print(i, "Buzz"))
                },
                new {
                    Condition = new Predicate(i => true),
                    Action = new Action(i => Print(i, ""))
                }
            };

            Enumerable.Range(0, 100).ForEach(i => fizzbuzz.Where(item => item.Condition(i)).First().Action(i));

Pretty slick.  Also note that Predicate<T> is exactly the same as Func<T,bool>.  I can't help but think, though, that this would be a lot simpler in F# :)  But that's another post (my F# skills are rusty at the moment).

Note that by no means am I advocating this functional approach is better than the standard procedural approach. It's certainly more complicated and takes a bit of time to really understand what's going on under the covers. It probably performs a lot worse too. I just thought it was neat to see things from a different approach.

Hope someone finds that useful!


You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

AddThis Social Bookmark Button

2 Responses to “FizzBuzz the Functional Way”

  1. Anyone worth their salt should be able to crank out a solution in a couple minutes.

    Hmmm. Your FizzBuzz has an off-by-1 error.

    for (int i = 0; i < 100; i++)

    should be:

    for (int i = 1; i <= 100; i++)

  2. Touche, Jim. Thanks :)

Leave a Reply