nope/lib/helpers/arrayMethods.ts
2021-08-17 17:52:46 +02:00

248 lines
6.2 KiB
TypeScript

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-11-06 08:53:00
* @modify date 2020-11-06 08:53:01
* @desc [description]
*/
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<any>} list List, where data should be extracted
* @param {string} path path pointing to the Data in the List
* @returns {Array<any>} List only containing the Elements.
*/
export function extractListElement(list: Array<any>, path: string): Array<any> {
// 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<T>} list
* @returns {Set<T>}
*/
export function toSet<T>(list: Array<T>): Set<T> {
const _ret = new Set<T>();
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<T>} 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<T>(list: Array<T>, 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<any>, b: Array<any>, considerOrder = true) {
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<T>(array: T[], element: T, maxElements: number) {
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<string> | Array<number> | Array<number | string>) {
const ret: { [index: string]: number } = {};
for (const element of array) {
const str = element.toString();
if (ret[str] === undefined) {
ret[str] = 1;
} else {
ret[str]++;
}
}
return ret;
}
/**
* Function, which will Flatten the Array.
* @param arrayToFlatten The Array
*/
export function flattenDeep<T>(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<T>(objToTest: T, array: Array<T>, 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<T, K>(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)
};
}