diff --git a/src/utils/uniq.ts b/src/utils/uniq.ts index d22f9eb..85a3517 100644 --- a/src/utils/uniq.ts +++ b/src/utils/uniq.ts @@ -1,13 +1,13 @@ const iterateeUniq = (arr: T[], iteratee: (value: T, i: number, arr: T[]) => U): T[] => { const result: T[] = [], - seen: U[] = []; + seen = new Set(); for (let i = 0, length = arr.length; i < length; i++) { const value = arr[i], computed = iteratee(value, i, arr); - if (seen.indexOf(computed) === -1) { - seen.push(computed); + if (!seen.has(computed)) { + seen.add(computed); result.push(value); } } @@ -33,11 +33,7 @@ const sortedUniq = (arr: T[]): T[] => { const standardUniq = (arr: T[]): T[] => { - const result = arr.filter((value, index, _arr) => { - return _arr.indexOf(value) === index; - }); - - return result; + return Array.from(new Set(arr)); }; diff --git a/tests/utils/uniq.test.ts b/tests/utils/uniq.test.ts index c4df57b..28b59d2 100644 --- a/tests/utils/uniq.test.ts +++ b/tests/utils/uniq.test.ts @@ -21,4 +21,47 @@ describe('uniq', () => { expect(uniq([ 4, 4, 1, 1, 2, 3, 4 ], false, isEven)).to.eql([ 4, 1 ]); }); + + it('handles 40,000 elements in under 50ms', () => { + const arr: string[] = []; + + for (let i = 0; i < 40000; i++) { + arr.push('item-' + (Math.random() < 0.3 ? i % Math.floor(40000 * 0.7) : i)); + } + + // Warmup to avoid JIT noise + uniq(arr); + + const start = performance.now(), + result = uniq(arr); + + expect(performance.now() - start).to.be.lessThan(50); + expect(result.length).to.be.greaterThan(0); + expect(result.length).to.be.lessThan(arr.length); + }); + + + it('handles 40,000 elements with iteratee in under 50ms', () => { + const arr: string[] = []; + + for (let i = 0; i < 40000; i++) { + arr.push('item-' + i); + } + + // Iteratee that produces many unique computed values, causing the + // seen array to grow large and indexOf to become O(n) + const iteratee = (v: string): string => { + return v + '-computed'; + }; + + // Warmup + uniq(arr, false, iteratee); + + const start = performance.now(), + result = uniq(arr, false, iteratee); + + expect(performance.now() - start).to.be.lessThan(50); + expect(result.length).to.strictlyEqual(40000); + }); + });