55 lines
2.1 KiB
Clojure
55 lines
2.1 KiB
Clojure
(ns challenge.discrete-value-range)
|
|
|
|
(defprotocol DiscreteValueRange
|
|
"A protocol for generic behavior on Ranges over
|
|
discrete values.
|
|
|
|
This is for discrete values as we want to be
|
|
able to determine the value before the range
|
|
start and the value immediately after the range end.
|
|
|
|
By using discrete values we:
|
|
1. Determine if two ranges abut (touch) each other, and
|
|
can therefore be combined into a single range
|
|
2. Can combine overlapping by listing all ranges' start
|
|
and end values, and using a stack's push/pop functionality
|
|
to know if we are in a larger composite range, similiar
|
|
to parenthesis matching. e.g. If I encounter two range
|
|
start items, I know I should be expecting two end values,
|
|
even if the range is 'unbounded', there should be a MIN/MAX
|
|
value specified.
|
|
3. Know the discrete values for both before and or after the range
|
|
(even if a MIN/MAX marker) value that we can use to compare
|
|
that before/after values against other values that the range
|
|
is over.
|
|
"
|
|
(abuts [this ^DiscreteValueRange other])
|
|
(value-before [this])
|
|
(value-after [this])
|
|
(start [this])
|
|
(end [this])
|
|
(range-type [this]))
|
|
|
|
(defn- ordered-range-values
|
|
"Builds an ordered list or 'fenceposts' for the start and end
|
|
of all given ranges, to prepare to produces a consolidated
|
|
set of ranges, by doing open/close count matching.
|
|
|
|
By building this list, it will allow us to push a `start`
|
|
onto a stack, and `pop` when we encounter an `end.`
|
|
|
|
If we pop, and get an empty stack, we have found the item
|
|
that represents the end value that matches the start value
|
|
that we just popped off the stack, and are able to ignore
|
|
any intermediate matching starts/stops."
|
|
[ranges]
|
|
(->> ranges
|
|
(mapcat (fn [range]
|
|
[{:value (start range)
|
|
:boundary-type :start
|
|
:type (range-type range)}
|
|
{:value (end range)
|
|
:boundary-type :end
|
|
:type (range-type range)}]))
|
|
(sort-by (juxt :value (comp {:start 0 :end 1} :boundary-type)))))
|