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:
2026-01-10 18:28:24 -06:00
parent 98761a79ea
commit d0c78810f0
2 changed files with 69 additions and 5 deletions

View File

@@ -28,7 +28,8 @@
(value-after [this])
(start [this])
(end [this])
(range-type [this]))
(range-type [this])
(union [range1 range2]))
(defn- ordered-range-values
"Builds an ordered list or 'fenceposts' for the start and end
@@ -56,7 +57,7 @@
(defmulti ->discrete-value-range (fn [range-type _start _end]
range-type))
(defn combine-overlapping-ranges
(defn- combine-overlapping-ranges
"transducer to find and combine overlapping ranges by looking at
ordered range value markers.
@@ -91,9 +92,41 @@
result
(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
(comp
(combine-overlapping-ranges)))
(combine-overlapping-ranges)
(combine-abutting-ranges)))
(defn consolidate [ranges]
(eduction consolidate-ranges-xf (ordered-range-values ranges)))