UNPKG

@mezzy/collections

Version:

A luxurious user experience framework, developed by your friends at Mezzanine.

213 lines (167 loc) 7 kB
import is from '@mezzy/is'; import { ICompareFunction, IEqualsFunction, ILoopFunction } from '@mezzy/function-types'; import ArrayTools from './arrayTools'; import IList from './interfaces/iList'; export class List<T> implements IList<T> { constructor(items?: T[]) { this.p_array = []; if (is.notEmpty(items)) { for (let i:number = 0; i < items.length; i++) { this.add(items[i]); } } } /*====================================================================* START: Static *====================================================================*/ static fromArray<T>(array:T[]):List<T> { let list:List<T> = new List<T>(); for (let i:number = 0; i < array.length; i++) { list.add(array[i]); } return list; } /*====================================================================* START: Properties *====================================================================*/ get isEmpty():boolean { return this.p_array.length <= 0; } get size():number { return this.p_array.length; } get first():T { return this.p_array[0]; } get last():T { return this.p_array[this.p_array.length]; } get array():Array<T> { return this.p_array; } protected p_array:Array<T>; item(index:number):T { let item:T = this.p_array[index]; return is.notEmpty(item) ? item : null; } /*====================================================================* START: Methods *====================================================================*/ indexOf(item:T, fromIndex:number = 0):number { return this.p_array.indexOf(item, fromIndex); } add(item:T, index?:number):void { if (is.empty(index)) index = this.p_array.length; if (index < 0 || index > this.p_array.length || is.empty(item)) return; this.p_array.splice(index, 0, item); } /** * Appends all the items in the provided list to this list. */ append(list:List<T>):void { if (is.empty(list)) return; list.forEach((item:T) => { if (is.notEmpty) { this.add(item); return true; } else return false; }); } copy():List<T> { let list:List<T> = new List<any>(); for (let index = 0; index < this.p_array.length; index++) { list.add(this.p_array[index]) } return list; } forEach(callback:ILoopFunction<T>):void { this.p_array.forEach(callback); } sort(compareFunction:ICompareFunction<T>):void { this.p_array.sort(compareFunction); } /** * Replaces/updates an element in this list. * Returns true if the element was replaced or false if the index is invalid or if the element is undefined. */ replace(item:T, index:number):void { this.p_array.splice(index, 1, item); } /** * Returns the index in this list of the first occurrence of the * specified element, or -1 if the List does not contain this element. * <p>If the elements inside this list are * not comparable with the === operator a custom equals function should be * provided to perform searches, the function must receive two arguments and * return true if they are equal, false otherwise. Example:</p> * * <pre> * let petsAreEqualByName = function(pet1, pet2) { * return pet1.key === pet2.key; * } * </pre> */ search(item:T, equalsFunction?:IEqualsFunction<T>):number { if (is.empty(equalsFunction)) equalsFunction = (a:T, b:T):boolean => { return a === b; }; if (is.empty(item)) return -1; for (let index = 0; index < this.p_array.length; index++) { if (equalsFunction(this.p_array[index], item)) return index; } return -1; } /** * Returns true if this list has the specified element. * <p>If the elements inside the list are * not comparable with the === operator a custom equals function should be * provided to perform searches, the function must receive two arguments and * return true if they are equal, false otherwise. Example:</p> * * <pre> * let petsAreEqualByName = function(pet1, pet2) { * return pet1.key === pet2.key; * } * </pre> */ has(item:T):boolean { return (this.p_array.indexOf(item) >= 0); } // has(item:T, equalsFunction?:IEqualsFunction<T>):boolean { // return (this.indexOf(item, equalsFunction) >= 0); // } /** * Removes the first occurrence of the specified element in this list. * <p>If the elements inside the list are * not comparable with the === operator a custom equals function should be * provided to perform searches, the function must receive two arguments and * return true if they are equal, false otherwise. Example:</p> * * <pre> * let petsAreEqualByName = (pet1, pet2) => { * return pet1.key === pet2.key; * } * </pre> */ delete(item:T, equalsFunction?:IEqualsFunction<T>):boolean { if (is.empty(equalsFunction)) equalsFunction = (a:T, b:T):boolean => { return a === b; }; if (this.p_array.length < 1 || is.empty(item)) return false; for (let index = 0; index < this.p_array.length; index++) { if (equalsFunction(this.p_array[index], item)) { this.p_array.splice(index, 1); return true; } } return false; } deleteAtIndex(index:number):T { if (index < 0 || index >= this.p_array.length) return undefined; let item:T = this.p_array[index]; this.p_array.splice(index, 1); return item; } clear():void { this.p_array.splice(0, this.p_array.length); } /** * Returns true if this list is equal to the given list. * Two lists are equal if they have the same elements in the same order. * @param {List} other the other list. * @param {function(Object,Object):boolean=} equalsFunction optional * function used to check if two elements are equal. If the elements in the lists * are custom objects you should provide a function, otherwise * the === operator is used to check equality between elements. * @return {boolean} true if this list is equal to the given list. */ equals(other:List<T>, equalsFunction?:IEqualsFunction<T>):boolean { if (is.empty(equalsFunction)) equalsFunction = (a:T, b:T):boolean => { return a === b; }; if (!(other instanceof List)) return false; if (this.size !== other.size) return false; for (let index = 0; index < this.p_array.length; index++) { if (!equalsFunction(this.p_array[index], other.array[index])) return false; } return true; } toString():string { return ArrayTools.toString(this.copy().array); } } // End class export default List;