import { isAnyArray } from 'is-any-array'; import max from 'ml-array-max'; import min from 'ml-array-min'; export interface ArrayRescaleOptions> { /** * @default 0 */ min?: number; /** * @default 1 */ max?: number; /** * If `true` and min or max is undefined take the min or max from input array. * @default false */ autoMinMax?: boolean; /** * Specify the output array. Can be the input array for in place modification. */ output?: T; } /** * Rescale an array into a range. */ export default function rescale>( input: T, options: ArrayRescaleOptions = {}, ): T | number[] { if (!isAnyArray(input)) { throw new TypeError('input must be an array'); } else if (input.length === 0) { throw new TypeError('input must not be empty'); } let output; if (options.output !== undefined) { if (!isAnyArray(options.output)) { throw new TypeError('output option must be an array if specified'); } output = options.output; } else { output = new Array(input.length); } const currentMin = min(input); const currentMax = max(input); if (currentMin === currentMax) { throw new RangeError( 'minimum and maximum input values are equal. Cannot rescale a constant array', ); } const { min: minValue = options.autoMinMax ? currentMin : 0, max: maxValue = options.autoMinMax ? currentMax : 1, } = options; if (minValue >= maxValue) { throw new RangeError('min option must be smaller than max option'); } const factor = (maxValue - minValue) / (currentMax - currentMin); for (let i = 0; i < input.length; i++) { output[i] = (input[i] - currentMin) * factor + minValue; } return output; }