Created
March 5, 2020 06:56
-
-
Save matthewdowney/b68a6a18111dc1db32fde69f1f42e5ec to your computer and use it in GitHub Desktop.
Lazy Clojure merge-sort that works on infinite sequences
This file contains hidden or 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
(defn merge-sort [keyfn series] | |
(let [pop-next | |
(fn [keyfn series] | |
(let [serie+fst (map (juxt rest first) series)] | |
(when-let [next-item (first (sort-by keyfn (keep second serie+fst)))] | |
(reduce | |
(fn [[series returning] [serie fst]] | |
;; "pop" next-item from the first series we see whose first | |
;; item is equal to next-item (there might be multiple, and | |
;; we'll just take the first) | |
(if (and (= fst next-item) (not returning)) | |
[(conj series serie) fst] | |
;; otherwise put the first item back in front of the series | |
(let [reconstructed (if fst (cons fst serie) serie)] | |
[(conj series reconstructed) returning]))) | |
[[] nil] | |
serie+fst))))] | |
(lazy-seq | |
(let [[series nxt] (pop-next keyfn series)] | |
(if nxt | |
(cons nxt (merge-sort keyfn series)) | |
[]))))) | |
(take 10 | |
(merge-sort | |
identity | |
[(map #(* 2 %) (range)) | |
(map #(* 3 %) (range)) | |
(map #(* 5 %) (range))])) | |
;=> (0 0 0 2 3 4 5 6 6 8) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment