-
Notifications
You must be signed in to change notification settings - Fork 126
Range iterator
jaawerth edited this page Sep 22, 2023
·
2 revisions
In order to operate over a numeric range, we have the for
form. However, sometimes you want an iterator; for instance when using
icollect
or accumulate
, you can't use for
directly; you need
something like this:
;; stateless iterator function, used as first return value from range fn bellow
(fn range-next* [[start end step] x]
(if (= step 0) (when (not= start end) x)
(let [x (+ x step)]
(when (or (and (< 0 step) (< x end))
(and (> 0 step) (> x end)))
x))))
(fn range [...]
"Create a Lua iterator from ?start to ?end (non-inclusive); increment by ?step
When ?step is omitted, defaults to 1
When ?end is omitted, (range x) is identical to (range 0 x 1)
When (= ?step 0), infinitely repeats ?start
When (= ?start ?end), returns an empty iterator"
{:fnl/arglist [?start ?end ?step]}
(let [(start end step) (case (values (select :# ...) ...)
(0) (values 0 (/ 1 0) 1)
(1 ?end) (values 0 ?end 1)
(2 ?start ?end) (values ?start ?end 1)
_ ...)]
(values range-next* [start end step] (- start step))))
This iterator supports infinite ranges (limited by Lua number precision), negative and stepped ranges:
(icollect [v (range) :until (= v 10)] v) ; => [0 1 2 3 4 5 6 7 8 9]
(icollect [v (range 10)] v) ; => [0 1 2 3 4 5 6 7 8 9]
(icollect [v (range 1 5)] v) ; => [1 2 3 4]
(icollect [v (range 1 -5)] v) ; => []
(icollect [v (range -1 5)] v) ; => [-1 0 1 2 3 4]
(icollect [v (range -1 -5)] v) ; => []
(icollect [v (range -5 -1)] v) ; => [-5 -4 -3 -2]
(icollect [v (range -5 -1 -1)] v) ; => []
(icollect [v (range -1 -5 -1)] v) ; => [-1 -2 -3 -4]
(do (var n 0)
(icollect [v (range -1 -5 0)
:until (= n 10)]
(do (set n (+ n 1))
v))) ; => [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1]
(do (var n 0)
(icollect [v (range -5 -1 0)
:until (= n 10)]
(do (set n (+ n 1))
v))) ; => [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5]
(do (var n 0)
(icollect [v (range -5 0 0)
:until (= n 10)]
(do (set n (+ n 1))
v))) ; => [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5]
(icollect [v (range 0)] v) ; => []
(icollect [v (range 0 0)] v) ; => []
(icollect [v (range 0 0 0)] v) ; => []