Skip to content

Instantly share code, notes, and snippets.

@wevre
Last active July 17, 2020 00:46
Show Gist options
  • Save wevre/7b437d56e6c1d798e382b75bed35d5d3 to your computer and use it in GitHub Desktop.
Save wevre/7b437d56e6c1d798e382b75bed35d5d3 to your computer and use it in GitHub Desktop.
Natural sort comparator in Clojure/ClojureScript
(ns natural-compare
^{:author "Mike Weaver"
:see-also [["https://gist.github.com/wilkerlucio/db54dc83a9664124f3febf6356f04509"
"Alphabetical/Natural sorting in Clojure/Clojurescript"]]
:doc "A comparator for natural sorting."}
(:require [clojure.string :as str]))
(defn split-digits
"Splits string into sequence of alternating text and numbers."
[s]
(let [parse-int #(Long/parseLong %) ;; for cljs, use #(js/parseInt %)
text (str/split s #"\d+")
nums (mapv parse-int (re-seq #"\d+" s))]
;; Padding `text` and `nums` with "" and -1, respectively, ensures resulting
;; sequence will start with text, end with a number, and consistently
;; alternate inbetween. The pad values sort lower than 'legit' values, so
;; when one string is a prefix of another, the shorter one sorts first.
(interleave (conj text "") (conj nums -1))))
(defn natural-compare
"Compares two strings with natural sorting."
[a b]
(or (->> (map compare (split-digits a) (split-digits b))
(drop-while zero?)
first)
0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment