Last active
January 10, 2020 05:00
-
-
Save ticean/937ee5c605ce783f86547d394fdc03c5 to your computer and use it in GitHub Desktop.
Clojure comparator for sorting maps on n fields with sort order.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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