Instantly share code, notes, and snippets.

# ericnormand/00 FizzBuzz.md

Last active November 27, 2020 14:21
Show Gist options
• Save ericnormand/ef7ffcfb451e1a97a1ce54955e60c0c5 to your computer and use it in GitHub Desktop.

FizzBuzz, but with no ifs

FizzBuzz is a classic interview exercise meant to filter out people who can't program. It tests that you can write conditionals, loops, and a basic modulo check for divisibility. While it seems kind of insulting to ask someone to solve such a trivial problem, imagine if the interviewee couldn't do it. It's a quick way to check for basic skill before wasting an hour in the interview.

This week, you're going to write FizzBuzz, but just to show off to the interviewer, you're not going to write any conditionals or loops. Just to be clear, that means no `if`, `when`, `cond`, or `case` expressions.

Here are the rules:

Write a function that is passed a sequence of integers.

For each integer, if it's divisible by 3, print "Fizz". If it's divisible by 5, print "Buzz". If it's divisible by both 3 and 5, print "FizzBuzz". Finally, if it's divisible by neither, print the number itself. Each printing should be on a separate line.

Email submissions to eric@purelyfunctional.tv before September 13, 2020. You can discuss the submissions in the comments below.

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (ns tst.demo.core (:use tupelo.core tupelo.test)) (defn div-3? [n] (zero? (rem n 3))) ; hidden `if` statement (defn div-5? [n] (zero? (rem n 5))) ; hidden `if` statement (defn fizzbuzz [n] (let [factors [(div-3? n) (div-5? n)] result (get {[true false] "Fizz" [false true] "Buzz" [true true] "FizzBuzz"} factors n)] ; default has hidden `if` result)) (dotest (is= [true false false true false false true] (mapv div-3? (thru -3 3))) (is= [true false false false false true false false false false true] (mapv div-5? (thru -5 5))) (is= ["FizzBuzz" -14 -13 "Fizz" -11 "Buzz" "Fizz" -8 -7 "Fizz" "Buzz" -4 "Fizz" -2 -1 "FizzBuzz" 1 2 "Fizz" 4 "Buzz" "Fizz" 7 8 "Fizz" "Buzz" 11 "Fizz" 13 14 "FizzBuzz"] (mapv fizzbuzz (thru -15 15))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn fizzbuzz [n] (let [fizzes (cycle ["" "" "Fizz"]) buzzes (cycle ["" "" "" "" "Buzz"]) pattern (map str fizzes buzzes) numbers (map str (rest (range)))] (take n (map #(some not-empty %&) pattern numbers)))) (doseq [x (fizzbuzz 100)] (println x))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn fizzbuzz [xs] (let [x (first xs)] (and x (let [div-3 (= (mod x 3) 0) div-5 (= (mod x 5) 0)] (and div-3 (print "Fizz")) (and div-5 (print "Buzz")) (and (not div-3) (not div-5) (print x)) (println) (recur (rest xs))))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn fizzbuzz [ns] (doseq [n ns] (prn (get {[0 nil] "Fizz" [nil 0] "Buzz" [0 0] "FizzBuzz"} [(get {0 0} (rem n 3)) (get {0 0} (rem n 5))] n))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (ns clojure-challenge.issue-394) (defn fizzbuzzer [x] (or (and (= 0 (mod x 15)) "fizzbuzz") (and (= 0 (mod x 5)) "buzz") (and (= 0 (mod x 3)) "fizz") (str x))) (defn -main "Main function" [] (println (->> (range 31) (map fizzbuzzer))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (defn fizzbuzz [n] (letfn [(f [[div s]] (and (zero? (mod n div)) s))] (or (some f [[15 "FizzBuzz"] [5 "Buzz"] [3 "Fizz"]]) n))) (defn print-fizzbuzz [ns] (dorun (map (comp println fizzbuzz) ns)))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 ;; First solution (defn fizz-buzz-or-number [x] ( ["FizzBuzz" x x "Fizz" x "Buzz" "Fizz" x x "Fizz" "Buzz" x "Fizz" x x] (mod x 15))) (defn fizz-buzz [xs] (doseq [x (map fizz-buzz-x xs)] (println x))) (comment (fizz-buzz (range 1 101)) (fizz-buzz [1 3 5 10 12 13 15]) ) ;; Alternative solution. ;; I like this better, but it works better for a continuous range of numbers (defn- make-seq "Makes a sequence that returns name at each nth element and nil for others" [name nth] (cycle (concat (repeat (dec nth) nil) [name]))) (def fizzes (make-seq "Fizz" 3)) (def buzzes (make-seq "Buzz" 5)) (def fizzbuzzes (make-seq "FizzBuzz" 15)) (def first-non-nil #(some identity %&)) ;; a lazy seq of FizzBuzzes, Fizzes, Buzzes, and numbers (def fizz-buzz-seq (map first-non-nil fizzbuzzes fizzes buzzes (iterate inc 1))) (defn fizz-buzz-range "Returns FizzBuzz elements from start (inclusive) to end (exclusive), where start defaults to 1." ([end] (fizz-buzz-range 1 end)) ([start end] {:pre [(< start end)]} (->> fizz-buzz-seq (drop (dec start)) (take (- end start))) )) ;; The fizz-buzz-range works well for continuous ranges as the original FizzBuzz problem. ;; This function is to satisfy the spec in the newsletter (ie. pass in integers that could ;; be non-continuous) (defn fizz-buzz-alternative [xs] (doseq [x (map #(first (fizz-buzz-range % (inc %))) xs)] (println x))) (comment (fizz-buzz-range 101) (fizz-buzz-range 100 201) (fizz-buzz-alternative [1 3 5 9 10 12 13 15]) )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (ns purely-functional-tv-challenges.n394-fizz-buzz (:require [clojure.string :as str])) (defn fizz-buzz-infinite-seq "Infinite fizz buzz sequence where each element is either \"Fizz\", \"Buzz\", \"FizzBuzz\", or a string representing a natural number" [] (let [fizzes (cycle ["" "" "Fizz"]) buzzes (cycle ["" "" "" "" "Buzz"]) fizzes-and-buzzes (map str fizzes buzzes) ints-as-strings (->> (range) (map inc) (map str))] (->> (map vector fizzes-and-buzzes ints-as-strings) ; Seq of pairs of strings ; The line below is where the conditional sneaks in, because we check ; whether the element is a fizz/buzz/fizzbuzz or just a "normal" number. ; If it's a "normal" number then the fizzes-and-buzzes element will be blank. (map #(drop-while str/blank? %) ,,,) ; (map first ,,,)))) (defn fizz-buzz "For each x in xs, print Fizz, Buzz, FizzBuzz, or the number itself, each on a new line. Assume all xs are 1 or greater." [xs] (let [fizz-buzz-seq (fizz-buzz-infinite-seq)] (doseq [x xs] (println (nth fizz-buzz-seq (dec x))))))

### jeremyvdw commented Sep 7, 2020

```(defn fizzbuzz [xs]
(let [fizz #(zero? (mod % 3))
buzz #(zero? (mod % 5))
fizz-buzz (every-pred fizz buzz)]
(reduce
(fn [res el]
(println (or (and (fizz-buzz el) "FizzBuzz")
(and (buzz el) "Buzz")
(and (fizz el) "Fizz")
el))
res)
nil
xs)))```

### KingCode commented Sep 7, 2020 • edited Loading

That’s an interesting question. We could probably say that using `or` or `and` is a direct use of conditionals since they output `if`s. I chose to avoid relying on decision branching in the code I write as per the instructions: so the ones you mention are certainly ok!

The instructions say 'loops and conditionals' are off-limits. Can you clarify what counts as a 'loop' for the purposes of this exercise? It seems like `for` might be out, but what about `map`, or other seq functions? (Or indeed, `doseq`)?

### ninjure commented Sep 8, 2020

```(defn fizzbuzz [n]
(let [m {[false false] n
[true  false] "fizz"
[false true ] "buzz"
[true  true ] "fizzbuzz"}]
(m [(zero? (mod n 3))
(zero? (mod n 5))])))```

### ninjure commented Sep 8, 2020

```(defn fizzbuzz [n]
(some identity
[(get ["fizzbuzz"] (mod n 15))
(get ["buzz"] (mod n 5))
(get ["fizz"] (mod n 3))
n]))```

### daveschoutens commented Sep 8, 2020 • edited Loading

```(defn fizzbuzz-val [n]
(get {0 (get {0 "FizzBuzz"} (mod n 15) "Fizz")} ;; Does the 'default' argument of `get` count as cheating? :-)
(mod n 3)
(get {0 "Buzz"} (mod n 5) n)))

(defn fizzbuzz [xs]
(doseq [x xs] (println (fizzbuzz-val x))))```

Or, if `doseq` is off-limits:

```;; same `fizzbuzz-val as above

(defn do-fizzbuzz
([x] (println (fizzbuzz-val x)))
([x & xs]
(do-fizzbuzz x)
(apply do-fizzbuzz xs)))

(defn fizzbuzz [xs]
(apply do-fizzbuzz xs))```

### mchampine commented Sep 8, 2020 • edited Loading

Or, if `doseq` is off-limits:

If doseq is too "loopy" then I would think recursion is too! :)

### werand commented Sep 8, 2020 • edited Loading

```(defn fizzbuzz [s]
(map (fn [n]
(get ["fizzbuzz"] (mod n 15)
(get ["fizz"] (mod n 3)
(get ["buzz"] (mod n 5)
n))))
s))```

### ericnormand commented Sep 13, 2020

The instructions say 'loops and conditionals' are off-limits. Can you clarify what counts as a 'loop' for the purposes of this exercise? It seems like `for` might be out, but what about `map`, or other seq functions? (Or indeed, `doseq`)?

Sorry to get to this so late! For me, personally, `doseq` is a loop, but `map` is not. As for `run!`, I'm not sure! I wanted to leave it a little ambiguous to see what people would come up with.

to join this conversation on GitHub. Already have an account? Sign in to comment