Skip to content

Instantly share code, notes, and snippets.

@ticean
Last active January 10, 2020 05:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ticean/937ee5c605ce783f86547d394fdc03c5 to your computer and use it in GitHub Desktop.
Save ticean/937ee5c605ce783f86547d394fdc03c5 to your computer and use it in GitHub Desktop.
Clojure comparator for sorting maps on n fields with sort order.
(defmacro map-fields-comparator
"Comparator for sorting maps by field. `kw-orders` must be pairs of keywords
on which to sort and a sort direction, either :asc or :desc.
Example:
(map-fields-comparator :id :asc :time :desc)
The above is fine for key values that are inexpensive to compute from the values
being sorted. If the key values are expensive to compute, it is better to
calculate them once for each value. See the \"decorate-sort-undecorate\" technique
described in the documentation for sort-by. For more information, see
https://clojure.org/guides/comparators#_multi_field_comparators"
[& kw-orders]
(let [asym (gensym)
bsym (gensym)
comps (loop [ret {:top [] :bottom []}
vvs (seq kw-orders)]
(if-not vvs
ret
(recur
(let [[field order] vvs
topvar (if (= order :asc) asym bsym)
botvar (if (= order :asc) bsym asym)]
(assoc ret :top (conj (:top ret) `(~field ~topvar))
:bottom (conj (:bottom ret) `(~field ~botvar))))
(next (next vvs)))))]
`(fn [~asym ~bsym] (compare ~(:top comps) ~(:bottom comps)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment