Skip to content

Instantly share code, notes, and snippets.

@toomasv

toomasv/range.red

Last active Jun 19, 2021
Embed
What would you like to do?
Range function for multiple datatypes
Red [
Author: "Toomas Vooglaid"
Date: 26-11-2017
]
range: function [val1 val2 /step stp /limit /enbase ebase /debase dbase /unicode][
stp+?: none
stp: any [stp either any [percent? val1 percent? val2] [1%][1]]
if any [all [block? stp zero? stp/3] zero? stp] [return none]
case [
debase [
unless binary? val1 [
either any-string? val1 [
val1: debase/base form val1 dbase
][
cause-error 'user 'message ["Only `any-string!` will be debased!"]
]
]
unless limit or binary? val2 [val2: debase/base val2 dbase]
]
enbase [
unless binary? val1 [val1: debase/base val1 ebase]
unless limit or binary? val2 [val2: debase/base val2 ebase]
]
]
if binary? val1 [
val1: to-integer val1 val2: to-integer val2
binary: true
ebase: any [ebase 16]
]
if all [
block? stp
any [date? val1 time? val1]
][
if negative? stp/3 [
cause-error 'user 'message ["Negative values not allowed in block step!"]
]
stp+?: either find stp '- [false][true]
]
if limit [
val2: either block? stp [
val: val1
val/(stp/1): val/(stp/1) + (val2 - 1 * pick reduce [stp/3 0 - stp/3] stp+?)
val
][
val1 + (val2 - 1 * stp)
]
]
rng: to-block case [
stp+? [pick reduce [val1 val2] stp+?]
(number? stp) or (time? stp) [pick reduce [val1 val2] stp+?: stp > 0]
true [stp+?: true val1]
]
comp: pick reduce [:<= :>=] (growing?: val1 < val2) xor stp+?
inc: pick reduce [:+ :-] either block? stp [growing? = stp+?][growing?]
addnext: pick reduce [:append :insert] stp+?
changing: pick reduce [val1 val2] stp+?
limit: pick reduce [val2 val1] stp+?
either block? stp [
while [
changing/(stp/1): changing/(stp/1) inc stp/3
limit comp changing
][
head addnext rng changing
]
][
while [limit comp changing: changing inc stp] [
head addnext rng changing
]
]
case [
binary [forall rng [
rng/1: either enbase [
system/words/enbase/base to-binary rng/1 ebase
][ to-binary rng/1]
]]
unicode [forall rng [to-char rng/1]]
]
rng
]
@toomasv

This comment has been minimized.

Copy link
Owner Author

@toomasv toomasv commented Nov 26, 2017

Examples

a) from down up

>> range 1 5
== [1 2 3 4 5]
>> range -4 3
== [-4 -3 -2 -1 0 1 2 3]

b) from up down

>> range 5 1
== [5 4 3 2 1]

In case of percents default step is 1%

>> range -5% 5% 
== [-5% -4% -3% -2% -1% 3.469446951954e-16% 1% 2% 3% 4%]

-3.469446951954e-16% should be reckognized as 0% :)
Percents can be mixed with floats and integers

>> range 3% -.02 
== [3% 2% 1% -3.469446951954e-16% -1%]
>> range 90% 1
== [90% 91% 92% 93% 94% 95% 96% 97% 98% 99% 100%]
>> range 1 90%
== [1 0.99 0.98 0.97 0.96 0.95 0.94 0.93 0.92 0.91]

For other datatypes (i.e. beside percent) default step is 1

>> range #"a" #"f"
== [#"a" #"b" #"c" #"d" #"e" #"f"]
>> range 1.2.3 4.5.6
== [1.2.3 2.3.4 3.4.5 4.5.6]
>> range 10x10 5x5
== [10x10 9x9 8x8 7x7 6x6 5x5]
>> range 2:00:00 2:00:05
== [2:00:00 2:00:01 2:00:02 2:00:03 2:00:04 2:00:05]
>> range 1-1-2017 5-1-2017
== [1-Jan-2017 2-Jan-2017 3-Jan-2017 4-Jan-2017 5-Jan-2017]

Steps

>> range/step 5 10 2
== [5 7 9]

Positive steps work in both directions starting on val1

>> range/step 10 5 2
== [10 8 6]

Negative numeric steps end on val2

>> range/step 5 10 -2
== [6 8 10]

For time and date recognized attributes may be used in block-steps

>> range/step 12:00 15:05 [hour + 2]
== [12:00:00 14:00:00]

Decrementing values work as negative numbers

>> range/step 12:00 15:05 [hour - 2]
== [13:05:00 15:05:00]

Negative values are not allowed in block-steps (to avoid infinite loops)

>> range/step 1-6-2017 5-1-2017 [month + -1]
*** User Error: "Negative values not allowed in block step!"

Other types of step can be used in appropriate cases

>> range/step 10x81 1x0 1x9
== [10x81 9x72 8x63 7x54 6x45 5x36 4x27 3x18 2x9 1x0]
>> range/step 1.1.1 5.10.15 1.2.3
== [1.1.1 2.3.4 3.5.7 4.7.10 5.9.13]
>> range/step 5.10.15 1.1.1 1.2.3
== [5.10.15 4.8.12 3.6.9 2.4.6 1.2.3]

Negative steps can't be used in some cases, but instead reversing the result may be used

>> reverse range/step 5.10.15 1.1.1 1.2.3
== [1.2.3 2.4.6 3.6.9 4.8.12 5.10.15]

Limits

With /limit val2 is interpreted as number of values in range.
Default step is 1 up.

>> range/limit 5 10
== [5 6 7 8 9 10 11 12 13 14]
>> range/limit 5% 5
== [5% 6% 7% 8% 9%]
>> range/limit 1.2.3 5
== [1.2.3 2.3.4 3.4.5 4.5.6 5.6.7]

/step will add gaps and determine direction

>> range/limit/step 5 10 5
== [5 10 15 20 25 30 35 40 45 50]
>> range/limit/step 1-1-2017 5 [month - 1]
== [1-Jan-2017 1-Dec-2016 1-Nov-2016 1-Oct-2016 1-Sep-2016]
>> range/limit/step 1-1-2017 5 -24:0:0
== [1-Jan-2017/0:00:00 31-Dec-2016/0:00:00 30-Dec-2016/0:00:00 29-Dec-2016/0:00:00 28-Dec-2016/0:00:00]
>> range/limit/step 1-1-2017 5 10 * 24:0:0
== [1-Jan-2017 11-Jan-2017/0:00:00 21-Jan-2017/0:00:00 31-Jan-2017/0:00:00 10-Feb-2017/0:00:00]

Binary values

>> range #{F9} #{FF}
== [#{000000F9} #{000000FA} #{000000FB} #{000000FC} #{000000FD} #{000000FE} #{000000FF}]
>> range 2#{00000001} 2#{00000011}
== [#{00000001} #{00000002} #{00000003}]
>> range 64#{AQ==} 64#{BQ==}
== [#{00000001} #{00000002} #{00000003} #{00000004} #{00000005}]
>> range/enbase 64#{AQ==} 64#{BQ==} 2
== ["00000000000000000000000000000001" "00000000000000000000000000000010" "00000000000000000000000000000011" "00000000000000000000000000000100"...
>> range/enbase 64#{AQ==} 64#{BQ==} 64
== ["AAAAAQ==" "AAAAAg==" "AAAAAw==" "AAAABA==" "AAAABQ=="]
>> range/enbase/limit 64#{AQ==} 3 64
== ["AAAAAQ==" "AAAAAg==" "AAAAAw=="]
>> range/limit 64#{AQ==} 3
== [#{00000001} #{00000002} #{00000003}]
>> range/limit/step 64#{AQ==} 5 2
== [#{00000001} #{00000003} #{00000005} #{00000007} #{00000009}]
@hiiamboris

This comment has been minimized.

Copy link

@hiiamboris hiiamboris commented Jun 18, 2021

Pair ranges are only useful as 2D ranges. E.g. range 2x2 4x4 should produce [2x2 3x2 4x2 2x3 3x3 4x3 2x4 3x4 4x4]

@toomasv

This comment has been minimized.

Copy link
Owner Author

@toomasv toomasv commented Jun 19, 2021

Probably you are right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment