Elixir Quiz

Weekly programming problems to help you learn Elixir

FizzBuzz

Welcome to the first ever Elixir Quiz problem. This week we will be tackling the classic interview question, FizzBuzz.

About FizzBuzz

I first heard about this problem several years ago while reading a blog post on Coding Horror. Since then I, as well as many other programmers I am sure, have used the problem to start learning new languages, as code kata, and as interview questions.

The problem is often chosen as an interview question as it is quite simple to implement, either as hand written psudocode or executable code. This makes it a good choice to filter out candidates who have little to no programming experience.

Since some of us will be using Elixir Quiz to take our first steps into the Elixir language, it makes sense to start with something simple and well understood.

The problem

The FizzBuzz problem is fairly straight forward.

Print the numbers from 1 to 100, replacing multiples of 3 with the word Fizz and multiples of 5 with the word Buzz. For numbers that are divisible by 3 and 5, replace the number with the word FizzBuzz.

So for example, 1 to 15 would look like:

1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz

How do I enter?

The FizzBuzz quiz runs from Saturday August 9th 2014 until Friday August 15th, 2014.

To enter, just complete the problem and post the code to our subreddit. For short solutions, you can put the code directly into your comment in the quiz thread.

For larger solutions, please host your code elsewhere and link to it.

GitHub gists can be useful for hosting your solutions, but anywhere is fine.

Example solutions

We got 3 solutions for this problem.

Two of the solutions involved pattern matching; Defining a function with 4 separate guard clauses to determine what string should be returned when a number is divisible by 15, 5, 3, or none of those.

def transform(value) when rem(value, 15) == 0, do: "FizzBuzz"
def transform(value) when rem(value, 3) == 0, do: "Fizz"
def transform(value) when rem(value, 5) == 0, do: "Buzz"
def transform(value), do: value

With the transform/1 function defined, both solutions took a range of numbers and mapped it to this function.

def up_to(n) do
  1..n
  |> Enum.to_list
  |> Enum.map(&transform/1)
  |> Enum.join " "
end

The other solution took a different approach, using two cycling Streams, zipping them, and transforming the result into the correct value using Stream.with_index/1.

defmodule FizzBuzz do

  @doc """
  Print the FizzBuzz sequence from 1 to `n`

  ## Example

      iex> FixxBuzz.up_to 20
      1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz Buzz 16 17 Fizz 19 Buzz
  """

  def up_to(n) do
    fizzbuzz_stream |> Enum.take(n) |> Enum.join |> IO.puts
  end

  @doc """
  Return a stream of FizzBuzz values
  """
  def fizzbuzz_stream do
    threes = Stream.cycle [ nil, nil, "Fizz " ]
    fives  = Stream.cycle [ nil, nil, nil, nil, "Buzz " ]
    Stream.zip(threes, fives) |> Stream.with_index |> Stream.map(&speak/1)
  end

  defp speak({{nil,  nil},  n}), do: "#{n+1} "
  defp speak({{fizz, buzz}, _}), do: "#{fizz}#{buzz}"

end