UNPKG

@jrc03c/js-math-tools

Version:
210 lines (164 loc) 3.91 kB
import { assert } from "./assert.mjs" import { isNumber } from "./is-number.mjs" import { isUndefined } from "./is-undefined.mjs" class RangeIterator { static from(data) { return new RangeIterator(data.a, data.b) } a = 0 b = 0 step = 0 constructor(a, b, step) { this.a = a this.b = b this.step = step ?? 1 } get length() { return Math.abs( (Math.max(this.a, this.b) - Math.min(this.a, this.b)) / this.step, ) } get pairIterator() { const iterator = this[Symbol.iterator]() function* helper() { let i = 0 for (const v of iterator) { yield [v, i] i++ } } return helper() } [Symbol.iterator]() { const shouldIncludeBigInts = typeof this.a === "bigint" || typeof this.b === "bigint" || typeof this.step === "bigint" const a = shouldIncludeBigInts ? BigInt(this.a) : this.a const b = shouldIncludeBigInts ? BigInt(this.b) : this.b let step = shouldIncludeBigInts ? BigInt(this.step) : this.step if ((a <= b && step < 0) || (a > b && step > 0)) { step *= shouldIncludeBigInts ? BigInt(-1) : -1 } function* helper() { if (a <= b) { for (let i = a; i < b; i += step) { yield i } } else { for (let i = a; i > b; i += step) { yield i } } } return helper() } drop(limit) { return new RangeIterator(this.a + limit * this.step, this.b) } every(fn) { for (const pair of this.pairIterator) { if (!fn(...pair)) { return false } } return true } filter(fn) { const out = [] for (const pair of this.pairIterator) { if (fn(...pair)) { out.push(pair[0]) } } return out } find(fn) { for (const pair of this.pairIterator) { if (fn(...pair)) { return pair[0] } } } flatMap() { throw new Error("The `RangeIterator.flatMap` method has no implementation!") } forEach(fn) { for (const pair of this.pairIterator) { fn(...pair) } } map(fn) { const out = [] for (const pair of this.pairIterator) { out.push(fn(...pair)) } return out } reduce(fn, out) { for (const pair of this.pairIterator) { out = fn(pair[0], out, pair[1]) } return out } some(fn) { for (const pair of this.pairIterator) { if (fn(...pair)) { return true } } return false } take(limit) { return new RangeIterator(this.a, this.a + limit * this.step) } toArray() { const out = [] for (const i of this) { out.push(i) } return out } } function range(a, b, step = 1) { assert( !isUndefined(a) && !isUndefined(b) && !isUndefined(step), "You must pass two numbers and optionally a step value to the `range` function!", ) assert( isNumber(a) && isNumber(b) && isNumber(step), "You must pass two numbers and optionally a step value to the `range` function!", ) assert( step !== 0, "The step value must be greater than 0! (NOTE: The step value is a magnitude; it does not indicate direction.)", ) return new RangeIterator(a, b, step) // let shouldReverse = false // const shouldIncludeBigInts = // typeof a === "bigint" || typeof b === "bigint" || typeof step === "bigint" // a = Number(a) // b = Number(b) // step = Number(step) // if (a > b) { // shouldReverse = true // const buffer = a // a = b + step // b = buffer + step // } // let out = [] // for (let i = a; i < b; i += step) { // if (shouldIncludeBigInts) { // try { // out.push(BigInt(i)) // } catch (e) { // out.push(i) // } // } else { // out.push(i) // } // } // if (shouldReverse) out = reverse(out) // return out } export { range, RangeIterator }