Skip to content

Instantly share code, notes, and snippets.

@matthewdowney
Created March 5, 2020 06:56
Show Gist options
  • Save matthewdowney/b68a6a18111dc1db32fde69f1f42e5ec to your computer and use it in GitHub Desktop.
Save matthewdowney/b68a6a18111dc1db32fde69f1f42e5ec to your computer and use it in GitHub Desktop.
Lazy Clojure merge-sort that works on infinite sequences
(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