From 725906c2e8bb457696d08eb7ec14b374cd6dbd5d Mon Sep 17 00:00:00 2001 From: Steven Proctor Date: Sat, 10 Jan 2026 17:19:28 -0600 Subject: [PATCH] create ordered sequence of the given ranges' start and end values --- src/challenge/discrete_value_range.clj | 26 +++++++++++++++++++- test/challenge/discrete_value_range_test.clj | 20 +++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/challenge/discrete_value_range.clj b/src/challenge/discrete_value_range.clj index 8193f30..a8dc9c0 100644 --- a/src/challenge/discrete_value_range.clj +++ b/src/challenge/discrete_value_range.clj @@ -27,4 +27,28 @@ (value-before [this]) (value-after [this]) (start [this]) - (end [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))))) diff --git a/test/challenge/discrete_value_range_test.clj b/test/challenge/discrete_value_range_test.clj index af1da3b..df51735 100644 --- a/test/challenge/discrete_value_range_test.clj +++ b/test/challenge/discrete_value_range_test.clj @@ -17,6 +17,8 @@ start) (end [_this] end) + (range-type [_this] + :int-range-inclusive) Object (toString [_this] @@ -51,3 +53,21 @@ (is (= 1 (range/start (int-range-inclusive 1 8))))) (testing "end" (is (= 8 (range/end (int-range-inclusive 1 8)))))) + +(deftest ordered-range-values + (testing "ordered range values are sorted by value and then the range's start boundary before any end boundary" + (is (= [{:value 4 :boundary-type :start :type :int-range-inclusive} + {:value 5 :boundary-type :start :type :int-range-inclusive} + {:value 5 :boundary-type :start :type :int-range-inclusive} + {:value 5 :boundary-type :end :type :int-range-inclusive} + {:value 5 :boundary-type :end :type :int-range-inclusive} + {:value 8 :boundary-type :end :type :int-range-inclusive}] + (#'range/ordered-range-values [(int-range-inclusive 4 5) + (int-range-inclusive 5 8) + (int-range-inclusive 5 5)]))) + (is (= [{:value 5 :boundary-type :start :type :int-range-inclusive} + {:value 5 :boundary-type :start :type :int-range-inclusive} + {:value 5 :boundary-type :end :type :int-range-inclusive} + {:value 5 :boundary-type :end :type :int-range-inclusive}] + (#'range/ordered-range-values [(int-range-inclusive 5 5) + (int-range-inclusive 5 5)])))))