export class ArrayUtils { /** * 比较两个数组中元素是否相同 * * @param array 被操作数组 * @param arr 用于比较的数组 */ static equal(array: T[], arr: ArrayLike): boolean { if (array.length !== arr.length) return false; const keys = Object.keys(arr); for (let i = 0, n = keys.length; i < n; i++) { const key = keys[i]; if (array[key] !== arr[key]) return false; } return true; } /** * 连接一个或多个数组到自身 * * @param array 被操作数组 * @param items 要添加到数组末尾的其他项。 * @returns 返回自身 */ static concatToSelf(array: T[], ...items: (T | ConcatArray)[]): T[] { let arr: T[] = []; items.forEach((v) => { arr = arr.concat(v); }); arr.forEach((v) => array.push(v)); return array; } /** * 使数组变得唯一,不存在两个相等的元素 * * @param array 被操作数组 * @param compare 比较函数 */ static unique(array: T[], compare = (a: T, b: T) => a === b): T[] { const keys = Object.keys(array); const ids = keys.map((v) => Number(v)).filter((v) => !isNaN(v)); const deleteMap: { [id: number]: true } = {}; // for (let i = 0, n = ids.length; i < n; i++) { const ki = ids[i]; if (deleteMap[ki]) continue; for (let j = i + 1; j < n; j++) { const kj = ids[j]; if (compare(array[ki], array[kj])) deleteMap[kj] = true; } } // for (let i = ids.length - 1; i >= 0; i--) { const id = ids[i]; if (deleteMap[id]) array.splice(id, 1); } return array; } /** * 使用b元素替换数组中第一个a元素。 * * @param array 被操作数组 * @param a 被替换的元素 * @param b 用于替换的元素 * @param isAdd 当数组中没有找到a元素时,是否需要把b元素添加到数组尾部。默认值为true。 */ static replace(array: T[], a: T, b: T, isAdd = true): T[] { let isreplace = false; for (let i = 0; i < array.length; i++) { if (array[i] === a) { array[i] = b; isreplace = true; break; } } if (!isreplace && isAdd) array.push(b); return array; } /** * 创建数组 * @param length 长度 * @param itemFunc 创建元素方法 */ static create(length: number, itemFunc: (index: number) => T): T[] { const arr: T[] = []; for (let i = 0; i < length; i++) { arr[i] = itemFunc(i); } return arr; } /** * 二分查找,如果有多个则返回第一个 * @param array 数组 * @param target 寻找的目标 * @param compare 比较函数 * @param start 起始位置 * @param end 结束位置 * @returns 查找到目标时返回所在位置,否则返回-1 */ static binarySearch(array: T[], target: T, compare: (a: T, b: T) => number, start?: number, end?: number): number { const insert = ArrayUtils.binarySearchInsert(array, target, compare, start, end); if (array[insert] === target) { return insert; } return -1; } /** * 二分查找插入位置,如果有多个则返回第一个 * @param array 数组 * @param target 寻找的目标 * @param compare 比较函数 * @param start 起始位置 * @param end 结束位置 * @returns 目标所在位置(如果该位置上不是目标对象,则该索引为该目标可插入的位置) */ static binarySearchInsert(array: T[], target: T, compare: (a: T, b: T) => number, start?: number, end?: number): number { if (start === undefined) start = 0; if (end === undefined) end = array.length; if (start === end) { return start; } if (compare(array[start], target) === 0) { return start; } const middle = ~~((start + end) / 2); if (compare(array[middle], target) < 0) { start = middle + 1; } else { end = middle; } return ArrayUtils.binarySearchInsert(array, target, compare, start, end); } /** * 判断数组是否唯一 * * @param array 被检查数组 * @param compare 比较函数 */ static isUnique(array: T[], compare = (a: T, b: T) => a === b): boolean { for (let i = array.length - 1; i >= 0; i--) { for (let j = 0; j < i; j++) { if (compare(array[i], array[j])) { return false; } } } return true; } /** * 删除元素 * * @param array 被操作数组 * @param item 被删除元素 * @returns 被删除元素在数组中的位置 */ static deleteItem(array: T[], item: T): number { const index = array.indexOf(item); if (index !== -1) array.splice(index, 1); return index; } }