
The most elegant implementation of FizzBuzz - viebel
http://klipse.ghost.io/the-most-elegant-implementation-of-fizzbuzz/
======
schoen
This is very nice. Here's my Python port:

    
    
      from itertools import cycle, imap, count, islice
      from operator import add
    
      def fizzbuzz(n):
          fizzes = cycle(["", "", "Fizz"])
          buzzes = cycle(["", "", "", "", "Buzz"])
          words = imap(add, fizzes, buzzes)
          numbers = imap(str, count(1))
          _fizzbuzz = imap(max, words, numbers)
          return list(islice(_fizzbuzz, n))

~~~
jimmahoney
Here's a different sort-of-functional python fizzbuzz.

While it doesn't use the spiffy lazy lists of itertools, and does have the
typical "if x % n == 0" test, it does generalize easily to the "and print Baz
every 37th number" case.

    
    
      def joinmap(func, elements, separator):
        return separator.join(map(func, elements))
    
      def fb_value(x, fb={3:'Fizz', 5:'Buzz'}):
        words = joinmap(lambda n: fb[n] if x % n == 0 else '', fb.keys(), '')
        return words if words else str(x)
    
      def fb_range(low=1, high=100):
        return joinmap(fb_value, range(low, 1 + high), '\n')
    
      print fb_range()

~~~
schoen
That's excellent!

Treating a dictionary as an iterator automatically iterates over its .keys(),
so you can remove the .keys() in fb.keys() and just map over fb itself.

>>> map(lambda x: x+x, {2: "who", 4: "do", 6: "we", 8: "appreciate"})

[16, 4, 8, 12]

A problem that this highlights is that the order in which the Fizz and Buzz
and other strings get concatenated depends on the order of the underlying
dictionary hash, which can be thought of as random. In Python 3 it even
changes from run to run.

[https://docs.python.org/3/whatsnew/3.3.html#summary-
release-...](https://docs.python.org/3/whatsnew/3.3.html#summary-release-
highlights)

$ python3 -c 'print(list({"foo": "bar", "baz": "qux"}))'

['foo', 'baz']

$ python3 -c 'print(list({"foo": "bar", "baz": "qux"}))'

['baz', 'foo']

For predictable behavior across larger sets of divisors, and for consistent
behavior on Python 3, you'd probably want to use collections.OrderedDict.

------
spacemanmatt
Not that I subscribe to 'elegance' but...this example was in a recent article
on core.match, and it's really terse:

    
    
      (with-out-str (doseq [n (range 1 11)]
        (println
          (match [(mod n 3) (mod n 5)]
                 [0 0] "FizzBuzz"
                 [0 _] "Fizz"
                 [_ 0] "Buzz"
                 :else n))))

------
AdieuToLogic
That's a slick way to remove the conditionals indeed. Inspired by it, here's a
Scala version (checked with v2.11):

    
    
      object Fizzbuzz
      {
          val fizzes = List (None, None, Some ("Fizz")).toStream;
          val buzzes = List (None, None, None, None, Some ("Buzz")).toStream;
          val reducer : (Option[String], Option[String]) => Option[String] =
              (a, b) => Option ((a ++ b).mkString).filterNot (_.isEmpty);
    
          def apply (amount : Int) : Seq[String] =
              Stream.continually (fizzes)
                  .flatten
                  .zip (Stream.continually (buzzes).flatten)
                  .map (reducer.tupled)
                  .zipWithIndex
                  .map {
                      case (s, n) => s.getOrElse ((n + 1).toString);
                      }
                  .take (amount);
      }
    
      Fizzbuzz (100).foreach (println)

~~~
viebel
It's amazing how scala syntax is verbose - not to say ugly!

~~~
AdieuToLogic
I was being intentionally verbose so that readers not familiar with Scala or
the collections types/methods used would have an easier time following it. I
also was avoiding use of pattern matching as they are cousins to conditionals
IMHO.

However, below is another version which employs idioms more commonly found:

    
    
      object Fizzbuzz
      {
          val fizzes = None :: None :: Some ("Fizz") :: Nil;
          val buzzes = None :: None :: None :: None :: Some ("Buzz") :: Nil;
    
          def apply (amount : Int) : TraversableOnce[String] =
          {
              val alternates = Stream.continually (fizzes).flatten
                .zip (Stream.continually (buzzes).flatten)
                .take (amount)
                .toArray;
    
              0.until (amount).map { n =>
                  alternates (n) match {
                      case (Some (f), Some (b)) => f + b;
                      case (Some (f), None) => f;
                      case (None, Some (b)) => b;
                      case _ => (n + 1).toString
                      }
                  }
          }
      }
    
      Fizzbuzz (100).foreach (println);

~~~
viebel
Oh! I see. It's much more concise and clean now.

But still I prefer the clojure version using pattern matching over the scala
one: [http://blog.klipse.tech/clojure/2016/10/25/core-
match.html#f...](http://blog.klipse.tech/clojure/2016/10/25/core-
match.html#fizzbuzz)

~~~
AdieuToLogic
Gotcha. Then here's a translation into Scala from the link you provided which
I believe maintains the spirit of the clojure version:

    
    
      object Fizzbuzz
      {
          def apply (amount : Int) : TraversableOnce[String] =
              1.to (amount).map { n =>
                  (n % 3, n % 5) match {
                      case (0, 0) => "FizzBuzz";
                      case (0, _) => "Fizz";
                      case (_, 0) => "Buzz";
                      case _ => n.toString
                      }
                  }
      }
      
      Fizzbuzz (100).foreach (println);
    
    

EDIT: When I said "Gotcha", I meant that as in "understood" and not in an
adversarial manner. Quite the opposite, actually, as this is a respectful
thread which I believe both parties have enjoyed.

------
ursus_bonum
All I've learned is I can't stand any code called "elegant."

~~~
milesvp
Probably a valid complaint against code like this. In an organization with a
lot of more junior developers I might strike this code in a code review as
being non obvious. On the other hand, I trust this code more than similar
basic conditional based fizzbuzz since there's no conditionals or nested logic
to get wrong. It's also simple to extend, ie, a 'Bazz' on 7 requirement would
be adding one more cycle to the mix.

------
cbhl
If you looked at the assembly code, though, there still is a branch (aka an if
statement) -- it's just hidden inside the "choice" function.

~~~
viebel
Indeed.

But I think that the point of functional programming is to provide a layer of
programming that exposes a clean API. You know: now side effects, no global
variables etc..

And maybe: no if!

