Home Reference Source

src/utils.ts

/**
 * Check if an `element` exists in given `array` or not
 */
export function arrContains(array: Array<any>, element: number|string): boolean {
    return array.indexOf(element) > -1;
}

/**
 * Creates a duplicate-free version of an array
 */
export function arrUnique(array: Array<any>): Array<any> {
    return array.filter((element, index, array) => array.indexOf(element) === index);
}

/**
 * Check the given `condition`, if `false`, throw exception with the given `message`
 */
export function assert(condition: boolean, message: any = 'Assertion failed!'): object|void {
    if (!condition) {
        throw new Error(message);
    }
}

/**
 * Return the given `dict` value by `key`. 
 * - If `key` is a `string`, return the value of `dict[key]` if exists, otherwise return the `defaultValue`
 * - If `key` is an `array`, use the last item of this array as `key` to query the value in `dict`
 * @param {stirng|Array<any>} key - used to query the `dict`
 * @param {any} defaultValue - default value
 */
export function getopt(dict: Array<any>, key: string|Array<any>, defaultValue:any): any {
    if (typeof(key) === 'string') {
        return dict[key] || defaultValue;
    } else if (Array.isArray(key)){
        let returnValue: any = defaultValue;
        for (let i = 0, len = key.length; i < len; i++) {
            let dictElementValue = dict[key[i]];
            if (typeof(dictElementValue) != 'undefined') {
                returnValue = dictElementValue;
            }
        }
        return returnValue;
    }
}

/**
 * Return a random float number between `a` and `b`
 */
export function randf(a: number, b: number): number {
    return Math.random() * (b - a) + a;
}

/**
 * Return a random integer number between `a` and `b`
 */
export function randi(a: number, b: number): number {
    return Math.floor(randf(a, b))
}

let gaussRandomReturnValue: boolean = false;
let gaussRandomValue: number = 0.0;
/**
 * Return a number by following Gaussian distribution by using Box-Muller Transform
 * - https://en.wikipedia.org/wiki/Box-Muller_transform
 * - https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve
 */
export function gaussRandom(): number {
    if (gaussRandomReturnValue) {
        gaussRandomReturnValue = false;
        return gaussRandomValue;
    }
    let u = 2 * Math.random() - 1;
    let v = 2 * Math.random() - 1;
    let r = u * u + v * v;
    if (r === 0 || r === 1) {
        return gaussRandom();
    }
    let c = Math.sqrt(-2*Math.log(r) / r);
    gaussRandomValue = v * c;
    gaussRandomReturnValue = true;
    return u * c;
};

/**
 * Return a random number based on the given `mean` and `standard deviation` by following Gaussian distribution 
 */
export function randn(mean: number, std: number): number {
    return mean + gaussRandom() * std;
}

/**
 * Return a series of 0
 */
export function zeros(n: number): Float64Array {
    return new Float64Array(n);
}

/**
 * Return the max/min information of a given value list.
 */
export function maxmin(values: number[]): object {
    if (values.length === 0) return {};
    let maxValue = Math.max(...values);
    let minValue = Math.min(...values);
    return {
        maxi: values.indexOf(maxValue),
        maxv: maxValue,
        mini: values.indexOf(minValue),
        minv: minValue,
        dv: maxValue - minValue
    };
};

/**
 * Generate a incrementing number list between 0 and `n`, shffle the list and return it as the result
 * - https://www.frankmitchell.org/2015/01/fisher-yates/
 */
export function randperm(n: number): Array<number> {
    let array = range(10);
    let i = 0;
    let j = 0;
    let temp = null;
    for (i = array.length - 1; i > 0; i -= 1) {
        j = Math.floor(Math.random() * (i + 1));
        temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}

/**
 * Return a sample of the given `array` by given `probabilities`
 */
export function weightedSample(array: Array<any>, probabilities: Array<number>): Array<any>|void {
    let probability = randf(0, 1.0);
    let cumulateProbability = 0.0;
    for (let k = 0, n = array.length; k < n; k++) {
        cumulateProbability += probabilities[k];
        if (probability < cumulateProbability) {
            return array[k];
        }
    }
}

/**
 * Return a zero based number list by given size `n`
 */
export function range(n:number = 0): number[] {
    return Array.from(Array(n).keys());
}