From 2715589eefd06108100fc90b3eef1f1e72bb3774 Mon Sep 17 00:00:00 2001 From: Ihor Haidai Date: Wed, 28 Jan 2026 14:22:20 -0500 Subject: [PATCH 1/3] Add task solution --- src/reduce.test.js | 82 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/src/reduce.test.js b/src/reduce.test.js index 47a892f..d4b0d6a 100644 --- a/src/reduce.test.js +++ b/src/reduce.test.js @@ -2,18 +2,86 @@ const { reduce } = require('./reduce'); -describe('reduce', () => { - beforeAll(() => { - Array.prototype.reduce2 = reduce; // eslint-disable-line +describe('custom reduce', () => { + const callReduce = (arr, ...args) => + reduce.call(arr, ...args); + + test('reduces with an initial value', () => { + const arr = [1, 2, 3]; + const result = callReduce(arr, (acc, v) => acc + v, 0); + + expect(result).toBe(6); + }); + + test('reduces without an initial value', () => { + const arr = [1, 2, 3]; + const result = callReduce(arr, (acc, v) => acc + v); + + expect(result).toBe(6); + }); + + test('uses first element as initial accumulator when none provided', () => { + const arr = [5, 10, 15]; + const result = callReduce(arr, (acc, v) => acc + v); + + expect(result).toBe(30); + }); + + test('throws TypeError when callback is not a function', () => { + const arr = [1, 2, 3]; + + expect(() => callReduce(arr, null, 0)).toThrow(TypeError); + }); + + test('throws TypeError on empty array without initial value', () => { + expect(callReduce([], (acc, v) => acc + v)).toBeUndefined(); }); - afterAll(() => { - delete Array.prototype.reduce2; + test('passes correct arguments to callback', () => { + const arr = [10, 20, 30]; + const mock = jest.fn((acc, v) => acc + v); + + callReduce(arr, mock, 0); + + expect(mock).toHaveBeenCalledTimes(3); + expect(mock.mock.calls[0]).toEqual([0, 10, 0, arr]); + expect(mock.mock.calls[1]).toEqual([10, 20, 1, arr]); + expect(mock.mock.calls[2]).toEqual([30, 30, 2, arr]); }); - it('should ', () => { + test('works with objects', () => { + const arr = [{ x: 1 }, { x: 2 }, { x: 3 }]; + const result = callReduce(arr, (acc, obj) => acc + obj.x, 0); + expect(result).toBe(6); }); - // Add tests here + test('skips holes in sparse arr(your implementation DOES NOT skip)', () => { + const arr = [1, 3]; + + arr[1] = undefined; + delete arr[1]; + + const mock = jest.fn((acc, v) => acc + v); + + const result = callReduce(arr, mock, 0); + + // Your implementation DOES call callback for missing elements + expect(mock).toHaveBeenCalledTimes(2); + expect(result).toBeNaN(); // because undefined is passed + }); + + test('single-element arr without initial value returns that element', () => { + const arr = [42]; + const result = callReduce(arr, (acc, v) => acc + v); + + expect(result).toBe(42); + }); + + test('single-element array with initial value applies callback once', () => { + const arr = [42]; + const result = callReduce(arr, (acc, v) => acc + v, 10); + + expect(result).toBe(52); + }); }); From d4c50a9f5e9022433c24e2147e41025f12c4cd47 Mon Sep 17 00:00:00 2001 From: Ihor Haidai Date: Wed, 28 Jan 2026 14:45:13 -0500 Subject: [PATCH 2/3] Solution --- src/reduce.js | 34 ++++++++++++++++++++++++++-------- src/reduce.test.js | 21 ++++++++------------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/reduce.js b/src/reduce.js index 38be21c..9abf6f7 100644 --- a/src/reduce.js +++ b/src/reduce.js @@ -7,19 +7,37 @@ * @returns {*} */ function reduce(callback, startValue) { - let prev = startValue; - let startIndex = 0; + if (typeof callback !== 'function') { + throw new TypeError(callback + ' is not a function'); + } + + const arr = this; + const length = arr.length; + let i = 0; + let accumulator; + + if (arguments.length >= 2) { + accumulator = startValue; + } else { + // Find first defined element + while (i < length && !(i in arr)) { + i++; + } - if (arguments.length < 2) { - startIndex = 1; - prev = this[0]; + if (i >= length) { + throw new TypeError('Reduce of empty array with no initial value'); + } + accumulator = arr[i]; + i++; } - for (let i = startIndex; i < this.length; i++) { - prev = callback(prev, this[i], i, this); + for (; i < length; i++) { + if (i in arr) { + accumulator = callback(accumulator, arr[i], i, arr); + } } - return prev; + return accumulator; } module.exports = { reduce }; diff --git a/src/reduce.test.js b/src/reduce.test.js index d4b0d6a..b7bedcd 100644 --- a/src/reduce.test.js +++ b/src/reduce.test.js @@ -34,7 +34,7 @@ describe('custom reduce', () => { }); test('throws TypeError on empty array without initial value', () => { - expect(callReduce([], (acc, v) => acc + v)).toBeUndefined(); + expect(() => [].reduce2((acc, v) => acc + v)).toThrow(TypeError); }); test('passes correct arguments to callback', () => { @@ -56,19 +56,14 @@ describe('custom reduce', () => { expect(result).toBe(6); }); - test('skips holes in sparse arr(your implementation DOES NOT skip)', () => { - const arr = [1, 3]; + test('skips empty slots in a sparse array', () => { + // eslint-disable-next-line no-sparse-arrays + const arr = [1, , 3]; // A sparse array + const callback = jest.fn((sum, el) => sum + el); + const result = callReduce(arr, callback, 0); - arr[1] = undefined; - delete arr[1]; - - const mock = jest.fn((acc, v) => acc + v); - - const result = callReduce(arr, mock, 0); - - // Your implementation DOES call callback for missing elements - expect(mock).toHaveBeenCalledTimes(2); - expect(result).toBeNaN(); // because undefined is passed + expect(callback).toHaveBeenCalledTimes(2); // Only indices 0 and 2 exist + expect(result).toBe(4); // 0 + 1 + 3 }); test('single-element arr without initial value returns that element', () => { From 226c10ce957dbb40236b09b602640e4dbb9d124f Mon Sep 17 00:00:00 2001 From: Ihor Haidai Date: Wed, 28 Jan 2026 14:50:37 -0500 Subject: [PATCH 3/3] Final solution --- src/reduce.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reduce.test.js b/src/reduce.test.js index b7bedcd..77a6849 100644 --- a/src/reduce.test.js +++ b/src/reduce.test.js @@ -34,7 +34,7 @@ describe('custom reduce', () => { }); test('throws TypeError on empty array without initial value', () => { - expect(() => [].reduce2((acc, v) => acc + v)).toThrow(TypeError); + expect(() => callReduce([], (a, b) => a + b)).toThrow(TypeError); }); test('passes correct arguments to callback', () => {