add transducer step to combine abutting ranges
ranges have previously been consolidated by having overlapping ranges be combined, resuting in a (possibly) consolidated set of ranges, which are now ordered by start and end dates. Add a transducer step to walk those ranges and find any pairs of ranges where the pair of ranges abutt each other, and combine them into a single range.
This commit is contained in:
@@ -28,7 +28,8 @@
|
|||||||
(value-after [this])
|
(value-after [this])
|
||||||
(start [this])
|
(start [this])
|
||||||
(end [this])
|
(end [this])
|
||||||
(range-type [this]))
|
(range-type [this])
|
||||||
|
(union [range1 range2]))
|
||||||
|
|
||||||
(defn- ordered-range-values
|
(defn- ordered-range-values
|
||||||
"Builds an ordered list or 'fenceposts' for the start and end
|
"Builds an ordered list or 'fenceposts' for the start and end
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
(defmulti ->discrete-value-range (fn [range-type _start _end]
|
(defmulti ->discrete-value-range (fn [range-type _start _end]
|
||||||
range-type))
|
range-type))
|
||||||
|
|
||||||
(defn combine-overlapping-ranges
|
(defn- combine-overlapping-ranges
|
||||||
"transducer to find and combine overlapping ranges by looking at
|
"transducer to find and combine overlapping ranges by looking at
|
||||||
ordered range value markers.
|
ordered range value markers.
|
||||||
|
|
||||||
@@ -91,9 +92,41 @@
|
|||||||
result
|
result
|
||||||
(xf result (->discrete-value-range (:type input) @start (:value input))))))))))))
|
(xf result (->discrete-value-range (:type input) @start (:value input))))))))))))
|
||||||
|
|
||||||
|
(defn- combine-abutting-ranges
|
||||||
|
"transducer to join ranges where the start and end of two ranges are consective
|
||||||
|
discrete values.
|
||||||
|
|
||||||
|
Assumes the ranges are already in order and any overlapping ranges have already been
|
||||||
|
combined."
|
||||||
|
[]
|
||||||
|
(fn [xf]
|
||||||
|
(let [prev (volatile! nil)]
|
||||||
|
(fn
|
||||||
|
([] (xf))
|
||||||
|
([result] (if @prev
|
||||||
|
(xf (xf result @prev))
|
||||||
|
(xf result)))
|
||||||
|
([result input]
|
||||||
|
(cond
|
||||||
|
(reduced? input) result
|
||||||
|
|
||||||
|
(nil? @prev) (do
|
||||||
|
(vreset! prev input)
|
||||||
|
result)
|
||||||
|
|
||||||
|
(abuts @prev input)
|
||||||
|
(let [item (union @prev input)]
|
||||||
|
(vreset! prev item)
|
||||||
|
result)
|
||||||
|
|
||||||
|
:else (let [item @prev]
|
||||||
|
(vreset! prev input)
|
||||||
|
(xf result item))))))))
|
||||||
|
|
||||||
(def consolidate-ranges-xf
|
(def consolidate-ranges-xf
|
||||||
(comp
|
(comp
|
||||||
(combine-overlapping-ranges)))
|
(combine-overlapping-ranges)
|
||||||
|
(combine-abutting-ranges)))
|
||||||
|
|
||||||
(defn consolidate [ranges]
|
(defn consolidate [ranges]
|
||||||
(eduction consolidate-ranges-xf (ordered-range-values ranges)))
|
(eduction consolidate-ranges-xf (ordered-range-values ranges)))
|
||||||
|
|||||||
@@ -19,6 +19,13 @@
|
|||||||
end)
|
end)
|
||||||
(range-type [_this]
|
(range-type [_this]
|
||||||
:int-range-inclusive)
|
:int-range-inclusive)
|
||||||
|
(union [this other]
|
||||||
|
(when-not (range/abuts this other)
|
||||||
|
(throw (ex-info "Cannot union non-abutting ranges" {})))
|
||||||
|
|
||||||
|
(range/->discrete-value-range (.range-type this)
|
||||||
|
(min start (.start other))
|
||||||
|
(max end (.end other))))
|
||||||
|
|
||||||
Object
|
Object
|
||||||
(toString [_this]
|
(toString [_this]
|
||||||
@@ -86,10 +93,10 @@
|
|||||||
(range/consolidate [(int-range-inclusive 5 5)
|
(range/consolidate [(int-range-inclusive 5 5)
|
||||||
(int-range-inclusive 5 5)])))
|
(int-range-inclusive 5 5)])))
|
||||||
(is (= [(int-range-inclusive 0 1)
|
(is (= [(int-range-inclusive 0 1)
|
||||||
(int-range-inclusive 2 7)
|
(int-range-inclusive 3 7)
|
||||||
(int-range-inclusive 9 11)]
|
(int-range-inclusive 9 11)]
|
||||||
(range/consolidate [(int-range-inclusive 0 1)
|
(range/consolidate [(int-range-inclusive 0 1)
|
||||||
(int-range-inclusive 2 4)
|
(int-range-inclusive 3 4)
|
||||||
(int-range-inclusive 3 7)
|
(int-range-inclusive 3 7)
|
||||||
(int-range-inclusive 5 5)
|
(int-range-inclusive 5 5)
|
||||||
(int-range-inclusive 9 11)
|
(int-range-inclusive 9 11)
|
||||||
@@ -99,4 +106,28 @@
|
|||||||
(int-range-inclusive 3 7)
|
(int-range-inclusive 3 7)
|
||||||
(int-range-inclusive 5 5)
|
(int-range-inclusive 5 5)
|
||||||
(int-range-inclusive 6 11)
|
(int-range-inclusive 6 11)
|
||||||
|
(int-range-inclusive 5 5)]))))
|
||||||
|
|
||||||
|
(testing "conjoins abutting ranges"
|
||||||
|
(is (= [(int-range-inclusive 0 9)]
|
||||||
|
(range/consolidate [(int-range-inclusive 0 1)
|
||||||
|
(int-range-inclusive 2 4)
|
||||||
|
(int-range-inclusive 5 5)
|
||||||
|
(int-range-inclusive 6 9)
|
||||||
|
(int-range-inclusive 5 5)])))
|
||||||
|
(is (= [(int-range-inclusive 0 9)]
|
||||||
|
(range/consolidate [(int-range-inclusive 0 1)
|
||||||
|
(int-range-inclusive 2 3)
|
||||||
|
(int-range-inclusive 4 5)
|
||||||
|
(int-range-inclusive 6 9)
|
||||||
|
(int-range-inclusive 5 5)]))))
|
||||||
|
|
||||||
|
(testing "combines overlapping ranges and conjoins abutting ranges"
|
||||||
|
(is (= [(int-range-inclusive 0 7)
|
||||||
|
(int-range-inclusive 13 17)]
|
||||||
|
(range/consolidate [(int-range-inclusive 0 1)
|
||||||
|
(int-range-inclusive 2 4)
|
||||||
|
(int-range-inclusive 3 7)
|
||||||
|
(int-range-inclusive 5 5)
|
||||||
|
(int-range-inclusive 13 17)
|
||||||
(int-range-inclusive 5 5)])))))
|
(int-range-inclusive 5 5)])))))
|
||||||
|
|||||||
Reference in New Issue
Block a user