I have a pair of vectors x
and y
of unique items, each of which I know to be sorted. I wish to have the intersection of the two, maintaining sort order
It is often the case that fast Clojure code looks a bit imperative. Functional code is often elegant, but comes with some associated performance costs that you have to pay for (laziness, extra GC pressure from discarded immutable objects etc.)
Also, converting into sets is always going to be more expensive. Building a set is an O(n log n)
operation in itself, but you can exploit the fact that the vectors are already supported to implement an intersection operation in O(n)
time.
Your code is already pretty good, but there are still a couple more optimisations you can do:
Resulting code might look something like:
(defn intersect-sorted-vector [x y]
(loop [i (long 0), j (long 0), r (transient [])]
(let [xi (nth x i nil), yj (nth y j nil)]
(cond
(not (and xi yj)) (persistent! r)
(< xi yj) (recur (inc i) j r)
(> xi yj) (recur i (inc j) r)
:else (recur (inc i) (inc j) (conj! r xi))))))
(time (count (intersect-sorted-vector x y)))
=> "Elapsed time: 5.143687 msecs"
=> 40258
So as you can see, this probably gives you an extra 6-8x speedup or thereabouts.