Assignment:
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".
First, explicit solution. The one wich I immediately conceive when hearing at the problem.
(for [x (range 1 (inc 100))]
(cond
(and (zero? (mod x 3)) (zero? (mod x 5))) "FizzBuzz"
(zero? (mod x 3)) "Fizz"
(zero? (mod x 3)) "Buzz"
:else x))
Then I present several progressive refinements. It's important for a code to be "given love". Given the context this code has to be inserted in, the preferred solution can change.
(for [x (range 1 (inc 100))]
(let [[divisible-by-3? divisible-by-5?] (->> [3 5]
(map #(mod x %))
(map zero?))]
(case [divisible-by-3? divisible-by-5?]
[true true] "FizzBuzz"
[true false] "Fizz"
[false true] "Buzz"
[false false] x)))
(for [x (range 1 (inc 100))]
(let [divisible-by-3? (if (-> 3 #(mod x %) zero?)
:divisible-by-3
:not-divisible-by-3)
divisible-by-5? (if (-> 5 #(mod x %) zero?)
:divisible-by-5
:not-divisible-by-5)]
(case [divisible-by-3? divisible-by-5?]
[:divisible-by-3 :divisible-by-5] "FizzBuzz"
[:divisible-by-3 :not-divisible-by-5] "Fizz"
[:not-divisible-by-3 :divisible-by-5] "Buzz"
[:not-divisible-by-3 :not-divisible-by-5] x)))
(defn- divisible-by?
[number divisor]
(let [division-rest (mod number divisor)
divisible? (zero? division-rest)]
(keyword (str (when-not divisible? "not-") "divisible-by-" divisor))))
(for [x (range 1 (inc 100))]
(let [divisible-by (partial divisible-by? x)]
(case [(divisible-by 3) (divisible-by 5)]
[:divisible-by-3 :divisible-by-5] "FizzBuzz"
[:divisible-by-3 :not-divisible-by-5] "Fizz"
[:not-divisible-by-3 :divisible-by-5] "Buzz"
[:not-divisible-by-3 :not-divisible-by-5] x)))
I would definitely go for a more declarative way:
(let [responses {#(zero? (mod % 3)) "Fizz"
#(zero? (mod % 5)) "Buzz"}]
(doseq [x (map inc (range 100))]
(doseq [[pred response] responses]
(when (pred x) (print response)))
(print "\n")))
If advised to use transducers, I would use:
(let [responses {#(zero? (mod % 3)) "Fizz"
#(zero? (mod % 5)) "Buzz"}]
(doall (eduction (map inc)
(map (fn [i]
(or (seq (mapcat (fn [[k v]]
(when (k i)
v))
responses))
[i])))
(map #(apply str %))
(map println)
(range 100))))
We are lucky enough to use Clojure, a terse, concise language. Anyone with any knowledge of progamming most probably understands what mod
is, so why going further?
(for [x (range 1 (inc 100))]
(cond
(and (zero? (mod x 3)) (zero? (mod x 5))) "FizzBuzz"
(zero? (mod x 3)) "Fizz"
(zero? (mod x 3)) "Buzz"
:else x))