Over the weekend, I published a simple class for creating numeric ranges. It's called NumRange
. It follows on from last week's post, but it's even better. Instead of creating entire arrays in memory, it returns an iterable NumRange
object. When the object is iterated over, e.g. in a for...of
loop, it yields the next value in the sequence from a generator function.
More accurately, the first time the generator function is called, it returns a Generator
object. When a value is consumed by calling the Generator
object's .next()
method, the generator function executes until it encounters the yield
keyword. This is repeated each time the .next()
method is called until the end of the generator function is reached. All of this is done internally by the for...of
loop, but it is possible to consume iterables directly.
The benefit of this is that it lets you perform operations on the NumRange
object without having to create the entire array. For example, I've written an .at()
method to get the value in the range at the given index, and an .includes()
method to check if a value exists in the range. The NumRange
object only keeps a reference to its .start
, .stop
, and .step
properties; the methods compute their return values from the values of these properties.
const range = new NumRange({ start: 1, stop: 6 });
// I can call these methods without creating the full array...
range.at(0); // 1
range.includes(3); // true
// I can also iterate over the range, possibly breaking early...
for (const num of range) {
console.log(num);
if (num === 3) break;
}
// I can use spread syntax too...
Math.max(...range); // 5
// And I can still create the full array if I want to...
const nums = Array.from(range); // [1, 2, 3, 4, 5]
I'll publish a detailed explanation next week, but many thanks to my colleague Simon for inspiring this post! He's not only a great developer in his own right, but also a brilliant mathematician and the creator of Mathematico. He pointed out to me that the range
type in Python works in a similar way, prompting me to create my NumRange
class. The following is taken directly from the Python docs:
The advantage of the
range
type over a regularlist
ortuple
is that arange
object will always take the same (small) amount of memory, no matter the size of the range it represents (as it only stores thestart
,stop
andstep
values, calculating individual items and subranges as needed).
I'll be back next week with a detailed explanation of my NumRange
class, iterators and generators, and iteration protocols!