Skip to content

Instantly share code, notes, and snippets.

@astoddard
Forked from jaycfields/gist:3796964
Created September 28, 2012 13:33
Show Gist options
  • Save astoddard/3799887 to your computer and use it in GitHub Desktop.
Save astoddard/3799887 to your computer and use it in GitHub Desktop.
less dry, easier to digest
(-> [jay john mike chris]
(->> (filter (comp (partial = "new york") :current-city)))
(->> (group-by :employer))
(update-in ["drw.com"] (partial map :name)))
@astoddard
Copy link
Author

I re-imagined the example using the clojure.set API, in the spirit of the previous blog post http://blog.jayfields.com/2012/09/replacing-common-code-with-clojureset.html

The output data is not the desired format, which was admittedly contrived, but I think this version shows the declaritive power of clojure.set:

(use 'clojure.set)
;;; the data we will start out with -
(def jay {:name "jay fields" :employer "drw.com" :current-city "new york"})
(def john {:name "john dydo" :employer "drw.com" :current-city "new york"})
(def mike {:name "mike ward" :employer "drw.com" :current-city "chicago"})
(def chris {:name "chris george" :employer "thoughtworks.com" :current-city "new york"})

;; make into a relation
(def folk #{jay john mike chris})

(-> folk
    (join #{{:current-city "new york" :employer "drw.com"}})
    (project [:name]))
;;=> #{{:name "john dydo"} {:name "jay fields"}}

(->> folk
     (join #{{:current-city "new york"}})
     (select (comp (partial not= "drw.com") :employer)))
;;=> #{{:employer "thoughtworks.com", :name "chris george", :current-city "new york"}}

@jaycfields
Copy link

While I was writing the entry I was thinking about clojure.set as well, but I didn't want to mix the two ideas. Thanks for the comment and bringing it all together. If we could easily use other keys, here's an example that gets us our desired output.

(def jay {:name "jay fields" :employer "drw.com" :current-city "new york"})
(def john {:name "john dydo" :employer "drw.com" :current-city "new york"})
(def mike {:name "mike ward" :employer "drw.com" :current-city "chicago"})
(def chris {:name "chris george" :employer "thoughtworks.com" :current-city "new york"})

(require 'clojure.set)

(-> #{jay john mike chris}
    (clojure.set/join #{{:current-city "new york"}})
    (clojure.set/index [:employer])
    (update-in [{:employer "drw.com"}] clojure.set/project [:name]))

;;; creates
{{:employer "thoughtworks.com"} #{{:employer "thoughtworks.com",
                                   :name "chris george",
                                   :current-city "new york"}},
 {:employer "drw.com"} #{{:name "john dydo"} {:name "jay fields"}}}</code>

@marxama
Copy link

marxama commented Sep 28, 2012

Nifty! I've bumped into the same issue before, and came up with a small, not that clever but occasionally useful macro:

(defmacro thr
  "Like the threading macros, but lets you provide a symbol to which the result
   of each successive form will be bound before calling the next. Example:

   (thr x value
     (fn1 :a :b x :c)
     (fn2 x :x :y x)
     (for [v x] (fn3 v)))" 
  ([sym x form]
    `(let [~sym ~x] 
       ~form))
  ([sym x form & more]
    `(thr ~sym (thr ~sym ~x ~form) ~@more)))

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