parzh / xrange

Python-esque iterator for number ranges
https://npmjs.org/package/xrange
0 stars 0 forks source link

Implement `.has` / `.includes` method #25

Open parzhitsky opened 4 years ago

parzhitsky commented 4 years ago

Example:

xrange(10).has(7); // true
xrange(2, -3).has(5); // false
const range = xrange(0, 10, 2);

range.has(6); // true
range.has(7); // false
range.has(8); // true

Functional implementation is just too unpredictable to have this functionality:

xrange(0, () => Math.random() > 0.5, () => 0).has(0);
// Error: cannot probe items of a non-deterministic range
// (even if `0` is clearly there, such predicate might make the whole range empty)
xrange(0, () => true, ([ last ]) => last === 6 ? CONSTANT : last + 1).has(7);
// Error: cannot probe items of a non-deterministic range
// (whether this range has 7 depends on the value of `CONSTANT`)
parzhitsky commented 4 years ago

This would require saving start, stop, and step of the range:

const { start, stop, step } = range;

let lower = false;
let upper = false;

if (step > 0)
    [ lower, upper ] = [ start <= x, x < stop ];

if (step < 0)
    [ lower, upper ] = [ stop < x, x <= start ];

if (!lower || !upper)
    return false; // out of bounds

return ((x - start) % step) === 0;
parzhitsky commented 4 years ago

Blocked by #59

parzhitsky commented 4 years ago

Though possible via Proxy, this won't be implemented as in operator, since such usage of the operator would be very confusing. Instead, .has() and/or .includes() method will be implemented.

The name .includes() (as in String.prototype.includes or Array.prototype.includes) seems more natural for such kind of task, but it creates false impression of under-the-hood iteration (i.e., O(n) computational complexity). On the other hand, .has() (as in Set.prototype.has) is a fast method (O(1), similar to "prop" in object); but doesn't seem so natural.

With this in mind, .has() will be the primary name for the method, and .includes() will be an alias for it:

xrange(1, 17, 3).has(4); // true