Clojure-Fu with Juxt

I love juxt1. But I was reminded yesterday that not everyone has made friends with it. So, to give it a little of the limelight it deserves, I thought I'd write down My Favourite Juxt Trick.

The Recap

First, let's recap what juxt does: it lets you pass the same arguments to several functions in a row. So if you want to find out a person's name & height, you can do this:

(def name-and-height
  (juxt :name :height))

name-and-height is now a single function that returns both results as in a vector:

(def person {:name "Kris"
             :height 172
             :devastating-handsomeness-factor 2})

(println
 (name-and-height person))
;=> [Kris 172]

Nothing special there. It's just calling each function, :name and :height, with the same arguments, and gathering up the results.

The Trick

Now let's do something cool with it. I've got a list of people working in different departments:

(def people [{:name "Brad"     :salary 27000 :department "hats"}
             {:name "Janet"    :salary 54000 :department "capes"}
             {:name "Eddie"    :salary 19500 :department "hats"}
             {:name "Frank"    :salary 98000 :department "capes"}
             {:name "Rocky"    :salary 18000 :department "shoes"}])

I'd like to roll those up by department and largesse. First let's define what counts as highly-paid, using a number that's entirely fictional in London:

  (defn highly-paid? [x]
    (< 30000 (:salary x)))

Now we have two functions, and we can group by both of them:

(pprint
 (group-by (juxt :department highly-paid?)
           people))
{["hats" false]
 [{:name "Brad", :salary 27000, :department "hats"}
  {:name "Eddie", :salary 19500, :department "hats"}],
 ["capes" true]
 [{:name "Janet", :salary 54000, :department "capes"}
  {:name "Frank", :salary 98000, :department "capes"}],
 ["shoes" false] [{:name "Rocky", :salary 18000, :department "shoes"}]}

There - we've just built an on-the-fly, composite-key index of our data, for free.

Any time you need to filter some data by multiple criteria, juxt comes in mighty handy.

Footnotes


  1. Sorry Juxt. I love you too, but this one is about your namesake.