Sunday, September 28, 2014

How to Get 2 and 4 OR Learning Clojure in Public

"One heart, one bed, two bosoms, and one troth"
-- Shakespeare, A Midsummer Night's Dream
Act II, Scene II, Line 48

I believe in "learning in public" and I've been inspired recently, after watching Uncle Bob's "The Last Programming Language",  going to Strange Loop 2014, and the release of The Joy of Clojure 2nd edition, I've decided to learn me a Clojure for great good.  I've been going through the 4clojure problems as my morning kata for a few weeks now and I've hit problem #52 earlier in the week.

Intro to Destructuring

Let bindings and function parameter lists support destructuring.

(= [2 4] (let [[a b c d e f g] (range)] __))

The answer is [c e] giving the following expression.

(= [2 4] (let [[a b c d e f g] (range)] [c e]))

which evaluates to true
As I understand it, the way this works is that let binding maps the values from range over a through g which gives the a the value 0, b the value 1, c the value of 2, ..., e the value of 4, and so on.  Since we are looking for a vector with the values of 2 and 4, a vector with c and e will give us the [2 4] we are looking for.

How else can we do this?

We could take range, remove the zero value and pipe it through a filter to get just even numbers and then take the 2 and 4.

range -> remove zero -> filter evens -> take first two

In Clojure this would look like this:

(->> (range) (rest) (filter even?) (take 2))

which evaluates to (2 4)

If you want it in a vector you would need to convert the list into a vector which could be done using into, which would look like this:

(->> (range) (rest) (filter even?) (take 2) (into []))

which evaluates to [2 4]

In SQL on SQL Server this would look like this:

 @min AS INT = 0
,@max AS INT = 100

;WITH [range] AS (
  SELECT @min AS num
  SELECT num + 1 FROM [range] WHERE num < @max

  FROM [range]
  WHERE num > 0
    AND (num % 2) = 0

which gives us the result with a projection containing 2 and 4. 

We are creating a Tally Table using a CTE (as seen in Vinay Pugalia linked blog post), which will gives us similar functionality as the range in Clojure (similar because Clojure's range is lazy loaded and thus can be infinite).  We then filter using the WHERE clause to remove the zero like we do with rest in Clojure, next we filter to just evens using the % operator comparing those results to fine when they equal zero (yes, this not the best way to do this but it is similar).  Last we take the first two results by using TOP with 2.

This is very similar to what I blogged about here on doing FizzBuzz in SQL Server.

There you have it, two different solutions in two different languages on two very different platforms to get the first two even numbers greater than zero.

Learning in public can be fun.