import { Prray } from './prray' export async function mapAsync( arr: Prray, func: (currentValue: T, index: number, array: Prray) => Promise | U, ): Promise { const result: U[] = [] await loop(arr, async (value, ix) => (result[ix] = await func(value, ix, arr)), {}) return result } export function map(prr: Prray, func: (currentValue: T, index: number, array: Prray) => U): U[] { const result: U[] = [] for (let ix = 0; ix < prr.length; ix++) { result.push(func(prr[ix], ix, prr)) } return result } export async function filterAsync( arr: Prray, func: (currentValue: T, index: number, array: Prray) => Promise | boolean, ): Promise { const result: T[] = [] await loop(arr, async (value, ix) => ((await func(value, ix, arr)) ? result.push(value) : null), {}) return result } export function filter(prr: Prray, func: (currentValue: T, index: number, array: Prray) => boolean): T[] { const result: T[] = [] for (let ix = 0; ix < prr.length; ix++) { const value = prr[ix] if (func(value, ix, prr)) { result.push(value) } } return result } export async function reduceAsync( prr: Prray, func: (accumulator: T, currentValue: T, index: number, prray: Prray) => T | Promise, ): Promise export async function reduceAsync( prr: Prray, func: (accumulator: T, currentValue: T, index: number, prray: Prray) => T | Promise, initialValue: T, ): Promise export async function reduceAsync( prr: Prray, func: (accumulator: U, currentValue: T, index: number, prray: Prray) => U | Promise, initialValue: U, ): Promise export async function reduceAsync( prr: Prray, func: (accumulator: any, currentValue: T, index: number, prray: Prray) => any | Promise, initialValue?: any, ): Promise { let pre = initialValue let ix = 0 if (initialValue === undefined) { pre = prr[0] ix = 1 } for (ix; ix < prr.length; ix++) { const current = prr[ix] pre = await func(pre, current, ix, prr) } return pre } export function reduce( prr: Prray, func: (accumulator: T, currentValue: T, index: number, array: Prray) => T, ): T export function reduce( prr: Prray, func: (accumulator: T, currentValue: T, index: number, array: Prray) => T, initialValue: T, ): T export function reduce( prr: Prray, func: (accumulator: U, currentValue: T, index: number, array: Prray) => U, initialValue: U, ): U export function reduce( prr: Prray, func: (accumulator: any, currentValue: T, index: number, array: Prray) => any, initialValue?: any, ): any { let pre = initialValue let ix = 0 if (initialValue === undefined) { pre = prr[0] ix = 1 } for (ix; ix < prr.length; ix++) { const current = prr[ix] pre = func(pre, current, ix, prr) } return pre } export async function reduceRightAsync( prr: Prray, func: (accumulator: T, currentValue: T, index: number, prray: Prray) => T | Promise, ): Promise export async function reduceRightAsync( prr: Prray, func: (accumulator: T, currentValue: T, index: number, prray: Prray) => T | Promise, initialValue: T, ): Promise export async function reduceRightAsync( prr: Prray, func: (accumulator: U, currentValue: T, index: number, prray: Prray) => U | Promise, initialValue: U, ): Promise export async function reduceRightAsync( prr: Prray, func: (accumulator: any, currentValue: T, index: number, prray: Prray) => any | Promise, initialValue?: any, ): Promise { let pre = initialValue let ix = prr.length - 1 if (initialValue === undefined) { pre = prr[prr.length - 1] ix = prr.length - 2 } for (ix; ix >= 0; ix--) { const current = prr[ix] pre = await func(pre, current, ix, prr) } return pre } export function reduceRight( prr: Prray, func: (accumulator: T, currentValue: T, index: number, array: Prray) => T, ): T export function reduceRight( prr: Prray, func: (accumulator: T, currentValue: T, index: number, array: Prray) => T, initialValue: T, ): T export function reduceRight( prr: Prray, func: (accumulator: U, currentValue: T, index: number, array: Prray) => U, initialValue: U, ): U export function reduceRight( prr: Prray, func: (accumulator: any, currentValue: T, index: number, array: Prray) => any, initialValue?: any, ): any { if (prr.length === 0) { if (initialValue === undefined) { throw TypeError('Reduce of empty array with no initial value') } else { return initialValue } } let pre = initialValue let ix = prr.length - 1 if (initialValue === undefined) { pre = prr[prr.length - 1] ix = prr.length - 2 } for (ix; ix >= 0; ix--) { const current = prr[ix] pre = func(pre, current, ix, prr) } return pre } export async function findIndexAsync( arr: Prray, func: (currentValue: T, index: number, array: Prray) => Promise | boolean, ): Promise { let result = -1 await loop( arr, async (value, ix, _, breakLoop) => { if (await func(value, ix, arr)) { result = ix breakLoop() } }, {}, ) return result } export function findIndex( prr: Prray, func: (currentValue: T, index: number, array: Prray) => boolean, ): number { const length = prr.length for (let ix = 0; ix < length; ix++) { if (func(prr[ix], ix, prr)) { return ix } } return -1 } export async function findAsync( arr: Prray, func: (currentValue: T, index: number, array: Prray) => Promise | boolean, ): Promise { let result: T | undefined await loop( arr, async (value, ix, _, breakLoop) => { if (await func(value, ix, arr)) { result = value breakLoop() } }, {}, ) return result } export function find( prr: Prray, func: (currentValue: T, index: number, array: Prray) => boolean, ): T | undefined { const length = prr.length for (let ix = 0; ix < length; ix++) { if (func(prr[ix], ix, prr)) { return prr[ix] } } return undefined } export async function everyAsync( prr: Prray, func: (currentValue: T, index: number, prray: Prray) => Promise | boolean, ): Promise { let result = true await loop( prr, async (value, ix, _, breakLoop) => { if (!(await func(value, ix, prr))) { result = false breakLoop() } }, {}, ) return result } export function every(prr: Prray, func: (currentValue: T, index: number, prray: Prray) => boolean): boolean { for (let ix = 0; ix < prr.length; ix++) { if (!func(prr[ix], ix, prr)) { return false } } return true } export async function someAsync( prr: Prray, func: (currentValue: T, index: number, prray: Prray) => Promise | boolean, ): Promise { let result = false await loop( prr, async (value, ix, _, breakLoop) => { if (await func(value, ix, prr)) { result = true breakLoop() } }, {}, ) return result } export function some(prr: Prray, func: (currentValue: T, index: number, prray: Prray) => boolean): boolean { for (let ix = 0; ix < prr.length; ix++) { if (func(prr[ix], ix, prr)) { return true } } return false } export async function sort(arr: Prray, func?: (a: T, b: T) => Promise | number): Promise { if (!func) { return [...arr].sort() } if (arr.length < 2) { return arr } // 插ε…₯ζŽ’εΊ for (let i = 1; i < arr.length; i++) { for (let j = 0; j < i; j++) { if ((await func(arr[i], arr[j])) < 0) { arr.splice(j, 0, arr[i]) arr.splice(i + 1, 1) break } } } return arr } export async function forEachAsync( prr: Prray, func: (currentValue: T, index: number, prray: Prray) => Promise | any, ): Promise { await loop(prr, async (value, ix) => func(value, ix, prr), {}) return } export function forEach(prr: Prray, func: (currentValue: T, index: number, prray: Prray) => any): undefined { for (let ix = 0; ix < prr.length; ix++) { func(prr[ix], ix, prr) } return } export function slice(arr: Prray, start = 0, end = Infinity): T[] { if (start === 0 && end === Infinity) { return arr } if (start > arr.length) { start = arr.length } if (start < -arr.length) { start = -arr.length } if (end > arr.length) { end = arr.length } if (end < -arr.length) { end = -arr.length } if (start < 0) { start = arr.length + start } if (end < 0) { end = arr.length + end } const result = [] for (let ix = start; ix < end; ix++) { result.push(arr[ix]) } return result } export function loop( array: Prray, func: (value: T, index: number, array: Prray, breakLoop: () => any) => any, { concurrency = Infinity }, ) { // FEATURE: options { concurrency, timeout, retries, defaults, fallback } if (array.length <= concurrency) { const promises = array.map((v, ix) => func(v, ix, array, () => null)) return Promise.all(promises) } return new Promise((resolve, reject) => { const length = array.length if (length === 0) { resolve() } let isEnding = false let currentIndex = 0 let workingNum = Math.min(concurrency, length) const breakLoop = () => { isEnding = true resolve() } const woker = async () => { while (!isEnding && currentIndex < length) { const ix = currentIndex++ try { await func(array[ix], ix, array, breakLoop) } catch (error) { isEnding = true reject(error) return } } workingNum-- if (workingNum === 0) { resolve() } } for (let i = 0; i < Math.min(concurrency, length); i++) { woker() } }) }