FizzBuzz is a famous recruitment interview question for programmers.
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”.
I imagine it can be used to weed out the ones who lied about everything on their application, since it is not exactly brain science nor rocket surgery.
Here’s an implementation of FizzBuzz in Common Lisp. LOOP is really a language onto itself, much like FORMAT (on which don’t get me started…) which I didn’t want (nor need) to use here. Output is done with PRINC, which simply prints its argument – and returns it, which we shall make use of later.
This implementation takes advantage of the fact that unlike COND, which exits as soon as a match is found, all the WHEN/UNLESS clauses get executed in sequence. The final DO does not have a condition, so it is executed on every iteration, bringing some legibility to the output by printing a space character. I used a character literal instead of the string ” ” because I could. TERPRI outputs a newline at the end of execution.
(loop for i from 1 to 100 when (integerp (/ i 3)) do (princ "Fizz") when (integerp (/ i 5)) do (princ "Buzz") when (not (or (integerp (/ i 3)) (integerp (/ i 5)))) do (princ i) do ; always (princ #\Space) finally (terpri))
Here’s the output:
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
Another way is to use a flag variable instead of repeating the tests. FIZZORBUZZ is reset to NIL on every iteration. When a test is triggered (I is divisible by 3 or 5), FIZZORBUZZ is set to the value of the PRINC statement, either “Fizz” or “Buzz”. The actual value is not important, as long as it is not NIL, in which case the UNLESS clause is triggered and I is output.
(loop for i from 1 to 100 for fizzorbuzz = nil when (integerp (/ i 3)) do (setq fizzorbuzz (princ "Fizz")) when (integerp (/ i 5)) do (setq fizzorbuzz (princ "Buzz")) unless fizzorbuzz do (princ i) do ; always (princ #\Space) finally (terpri))
It is debatable whether the above use of SETQ with the return value of PRINC is legible enough; it might be confusing if you don’t remember what PRINC returns. (It returns its argument.) It could be also written as (PROGN (PRINC “Fizz”) (SETQ FIZZORBUZZ T)).
Yet another way is to use two flag variables. This might be the most legible version yet; what do you think?
(loop for i from 1 to 100 for fizz = (integerp (/ i 3)) for buzz = (integerp (/ i 5)) when fizz do (princ "Fizz") when buzz do (princ "Buzz") unless (or fizz buzz) do (princ i) do ; always (princ #\Space) finally (terpri))
Finally, here is a version that works for any number of divisors and any sequence of consecutive (positive) integers. This version is unfortunately not as immediately obvious as the previous one.
The LET is there purely to avoid writing LOOP FOR I FROM FROM TO TO, which would be syntactically correct, but not exactly legible.
On each loop iteration, RESULT gets set to a list of test results. This is done by using MAPCAN to iterate over the list TESTS, which contains lists of divisor-message pairs. (The use of dotted pairs instead of lists could also be argued.) The anonymous LAMBDA function splits the pairs into the divisor and the message using DESTRUCTURING-BIND and checks whether the loop variable I is divisible by the divisor. If it is, the message is returned, otherwise NIL.
After MAPCAN is done, we have a list containing strings, or NIL. If NIL, the loop variable I was not divisible by any of the divisors in TESTS, and the value of I is stored in ANSWER. Otherwise the strings in the list are concatenated together, and the resulting string is stored.
When we have reached the end, the results are output by the FINALLY clause. I gave in and used FORMAT here for its nice iteration feature. Yes, there is an extra space at the end; removing it is left as an exercise to the reader, as is coming up with a more concise and/or readable version.
(defun fizzbuzz (&key (from 1) (to 100) (tests '((3 "Fizz") (5 "Buzz")))) (let ((start from) (finish to)) (loop for i from start to finish for result = (mapcan #'(lambda (test) (destructuring-bind (divisor message) test (when (integerp (/ i divisor)) (list message)))) tests) collect (if result (apply #'concatenate 'string result) i) into answer finally (format t "~{~A ~}~%" answer))))
Edit 2018-03-02: There’s not really much point in using COLLECT since all we’re doing with the list is printing it out at the end. Let’s get rid of it:
(defun fizzbuzz (&key (from 1) (to 100) (tests '((3 "Fizz") (5 "Buzz")))) (let ((start from) (finish to)) (loop for i from start to finish for result = (mapcan #'(lambda (test) (destructuring-bind (divisor message) test (when (integerp (/ i divisor)) (list message)))) tests) do (princ (if result (apply #'concatenate 'string result) i)) (princ #\Space) finally (terpri))))
And here’s how you might use this function version of FIZZBUZZ:
(fizzbuzz :to 105 :tests '((3 "Fizz") (5 "Buzz") (7 "Duck"))))
1 2 Fizz 4 Buzz Fizz Duck 8 Fizz Buzz 11 Fizz 13 Duck FizzBuzz 16 17 Fizz 19 Buzz FizzDuck 22 23 Fizz Buzz 26 Fizz Duck 29 FizzBuzz 31 32 Fizz 34 BuzzDuck Fizz 37 38 Fizz Buzz 41 FizzDuck 43 44 FizzBuzz 46 47 Fizz Duck Buzz Fizz 52 53 Fizz Buzz Duck Fizz 58 59 FizzBuzz 61 62 FizzDuck 64 Buzz Fizz 67 68 Fizz BuzzDuck 71 Fizz 73 74 FizzBuzz 76 Duck Fizz 79 Buzz Fizz 82 83 FizzDuck Buzz 86 Fizz 88 89 FizzBuzz Duck 92 Fizz 94 Buzz Fizz 97 Duck Fizz Buzz 101 Fizz 103 104 FizzBuzzDuck
One Reply to “FizzBuzz in Common Lisp”