/** * @author Martin Karkowski * @email m.karkowski@zema.de */ import { rgetattr } from "./objectMethods"; /** * Sorts a List based on the given property * Usage : * a = [{a : 1, b: 2}, {a : 2, b: 1}]; * b = a.sort(dynamicSort('b')) * b => [{a : 2, b: 1}, {a : 1, b: 2}] * * @export * @param {string} _property Property Name / Path to Sort the List * @returns */ export function dynamicSort(_property: string, reverse = false): any { const _sortOrder = reverse ? -1 : 1; return function (a, b) { const _a = rgetattr(a, _property); const _b = rgetattr(b, _property); if (typeof _a === "number" && typeof _b === "number") { const result = _a < _b ? -1 : _a > _b ? 1 : 0; return result * _sortOrder; } else if (typeof _a === "number") { return 1 * _sortOrder; } else if (typeof _b === "number") { return -1 * _sortOrder; } else if (typeof _a === "string" && typeof _b === "string") { return _a < _b ? -1 : _a > _b ? 1 : 0; } return 0; }; } /** * Extracts the Data of the given List * @export * @param {Array} list List, where data should be extracted * @param {string} path path pointing to the Data in the List * @returns {Array} List only containing the Elements. */ export function extractListElement(list: Array, path: string): Array { // Define Function to extract the Properties. function _extract(_property) { const _ret = rgetattr(_property, path); /** Returns the Value if it is in the Element */ if (_ret) { return _ret; } } return list.map(_extract); } /** * Converts a List to Set * * @export * @template T * @param {Array} list * @returns {Set} */ export function toSet(list: Array): Set { const _ret = new Set(); for (const item of list) { _ret.add(item); } return _ret; } /** * Extracts the first Element if Possible, which includes the Operand * * const a = [{path:'hallo'}, {path:'hallo2'}] * * getElement(a, 'hallo2', 'path') * * @export * @template T * @param {Array} list The list which is considered * @param {*} operand The Element which should looked for * @param {string} [path=''] The where the Element should be found * @returns {(T | null)} */ export function getElement( list: Array, operand: any, path = "" ): T | null { /** Iterate through the List an get the requested Element if possible */ for (const _element of list) { /** Compare the Requested value with the value of the List-Item */ if (operand === rgetattr(_element, path)) { return _element; } } return null; } /** * Function that will compare two arrays, if they are equal. * @param a Array Element A * @param b Array Element B * @param considerOrder Flag to enable/disable Order checking */ export function arraysEqual( a: Array, b: Array, considerOrder = true ): boolean { if (a === b) return true; if (a == null || b == null) return false; if (a.length != b.length) return false; let _a = a; let _b = b; if (!considerOrder) { _a = a.concat().sort(); _b = b.concat().sort(); } for (let i = 0; i < _a.length; ++i) { if (_a[i] !== _b[i]) return false; } return true; } /** * Function which will limit the Amount of Element stored in the Array during * pushing a new Element. If the Maximum is exited the Elementes will be removed * with the FIFO Principal. * @param array The considered Array * @param element The Element which should be added * @param maxElements The Max. Amount of Elements, which are allowed to store. */ export function limitedPush( array: T[], element: T, maxElements: number ): void { array.push(element); if (array.length > maxElements) { array.splice(0, 1); } } /** * Function to count the Number of Element in an Array. A Dict with the Elements * as string will be returned. * @param array The Array */ export function countElements(array: Array): Map { const ret: Map = new Map(); for (const element of array) { ret.set(element, (ret.get(element) || 0) + 1); } return ret; } /** * Function, which will Flatten the Array. * @param arrayToFlatten The Array */ export function flattenDeep(arrayToFlatten) { return arrayToFlatten.reduce( (acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), [] ) as T[]; } /** * Function, to Test whether the Element is present in the Array * @param objToTest The Object to Test * @param array The array to consider * @param path The path, under which the element will be found */ export function elementInArray(objToTest: T, array: Array, path: string) { const testData = rgetattr(objToTest, path, false); for (const [idx, element] of array.entries()) { if (testData === rgetattr(element, path, true)) { return idx; } } return -1; } /** * Function to ZIP to Arrays. * @param arr1 * @param arr2 */ export function zipArrays(arr1: T[], arr2: K[]): Array<[T, K]> { if (arr1.length !== arr2.length) { throw Error("Length of the Elements doesnt match!"); } const res: Array<[T, K]> = arr1.map(function (e, i) { return [e, arr2[i]]; }); return res; } /** * Helper to determine the average of an array * * @author M.Karkowski * @export * @param {any[]} arr * @param {string} path * @param {number} [defaultValue=0] * @return {*} {number} */ export function avgOfArray(arr: any[], path: string, defaultValue = 0): number { if (arr.length === 0) { return defaultValue; } const arrOfValues = arr.map((item) => rgetattr(item, path, defaultValue)); const added = arrOfValues.reduce((prev, curr) => prev + curr) as number; return added / arr.length; } export function minOfArray( arr: any[], path: string, defaultValue = 0 ): { min: number; index: number; } { if (arr.length === 0) { return { min: defaultValue, index: -1, }; } const arrOfValues = arr.map((item) => rgetattr(item, path, defaultValue) ) as number[]; const min = Math.min(...arrOfValues); return { min, index: arrOfValues.indexOf(min), }; } export function maxOfArray( arr: any[], path: string, defaultValue = 0 ): { max: number; index: number; } { if (arr.length === 0) { return { max: defaultValue, index: -1, }; } const arrOfValues = arr.map((item) => rgetattr(item, path, defaultValue) ) as number[]; const max = Math.max(...arrOfValues); return { max: max, index: arrOfValues.indexOf(max), }; }