Welcome! Please see the About page for a little more info on how this works.

0 votes
in Sequences by

Range is exclusive of the end argument. For example:

> (range 1 3)
(1 2)

I'd like a function that's like range, but is inclusive of the end state:

> (inclusive-range 1 3)
(1 2 3)

Unfortunately, this isn't the same as adding the end to the seq returned by range. For example:

> (inclusive-range 1 2.5)
(1 2)

I don't believe there's anything directly in Clojure that offers this, but I've found it handy. I've written a function that works (but is not lazy).

(defn inclusive-range
  "Return a sequence of nums from START to END, both inclusive, by STEP."
  ([start end]
   (inclusive-range start end 1))
  ([start end step]
   (let [test-for-done (if (< start end)
                         >
                         <)]
     (if (test-for-done start (+ start step))
       []
       (loop [nums []
              cur start]
         (if (test-for-done cur end)
           nums
           (recur (conj nums cur)
                  (+ cur step))))))))

Am I missing a better way to do this? Is this something that could be added to Clojure?

2 Answers

+1 vote
by

I often need something like this and so wrote the thru function:

`
tupelo.core/thru

(thru end)
(thru start end)
(thru start end step)

Returns a sequence of numbers. Like clojure.core/rng, but is inclusive of the right boundary value. Not lazy.
`

0 votes
by

One quick thought, though I'm not 100% sure I understand all your requirements/thoughts:

> (defn inclusive-end-range 
    [start end]
    (range start (inc end)))
#'inclusive-end-range
> (inclusive-end-range 1 3)
(1 2 3)
by
The OP specifically covered that case:

Unfortunately, this isn't the same as adding the end to the seq returned by range. For example:

> (inclusive-range 1 2.5)
(1 2)

(range 1 (inc 2.5)) => (1 2 3) instead.
by
Seems like that would be covered by `floor`, so `#(range %1 (inc (Math/floor %2)))`. Gets a bit more involved when the step argument is added, but also doable and simpler than the original `loop`-based solution.
by
Sean, you're so right - I misread that. Thanks for clarifying and sorry for the noise.
by
I was going to write an answer, but realized I can’t because the question is ill-posed, and this discussion shows why. Talking about “including the end” becomes meaningless when you start using fractional values for `end`. The example `(inclusive-range 1 2.5)` visibly does *not* include the end, even in the original question. So if the desired behavior of the function can be specified precisely, it will be straightforward to implement it by transforming the arguments and passing them to `range`. As mentioned by Eugene Pakhomov, it probably involves a combination of adding the step value to `end` and using `floor` on the result to derive the `end` value to pass to `range`.
...