From e2d0aff3e957f2d08996693538fcc6e39bb90a4c Mon Sep 17 00:00:00 2001 From: Andrei Navumau Date: Sat, 15 Mar 2025 15:45:10 -0400 Subject: [PATCH 1/4] Update solution and tests for Sprint 1 'fix' exercise with median --- Sprint-1/fix/median.js | 25 +++++++++++++++++-------- Sprint-1/fix/median.test.js | 27 +++++++++++++++++---------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index 677c9c7ff..aef3f27af 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -11,18 +11,27 @@ // } // Explanation: -// .splice() is a mutating method, so it updates the array in place. -// to prevent this, you could take a copy of the array and use .splice(), -// or you could use bracket notation to element at the desired index +// The original implementation has several mistakes: +// 1 - .splice() mutates or changes the original array. We don't want this to happen. +// 2 - We actually don't need .splice() or any other method to find a median. +// 3 - We must sort the array before we search for the median. +// 4 - We should check if the 'list' parameter actually has numbers, otherwise try to filter +// out all non-numeric values or throw an error if there are no numeric values. function calculateMedian(list) { - const middleIndex = Math.floor(list.length / 2); + const onlyNumberList = list.filter(item => typeof item === 'number' && !isNaN(item)); - if (list.length % 2 === 0) { // use the remainder operator (%) to check if the array length is even - return (list[middleIndex - 1] + list[middleIndex]) / 2; + if (!onlyNumberList.length) { + throw new Error('You provided a list without numbers.'); + } else { + const sortedList = onlyNumberList.sort((current, next) => current - next); + const indexNearMiddleOfArray = Math.floor(sortedList.length / 2); + if (sortedList.length % 2 === 0) { + return (sortedList[indexNearMiddleOfArray - 1] + sortedList[indexNearMiddleOfArray]) / 2; + } else { + return sortedList[indexNearMiddleOfArray]; + } } - - return list[middleIndex]; } module.exports = calculateMedian; diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 26817155c..05fa35f4a 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -7,20 +7,27 @@ const calculateMedian = require("./median.js"); describe("calculateMedian", () => { - it("returns the median for odd length array", () => { - expect(calculateMedian([1, 2, 3])).toEqual(2); - expect(calculateMedian([1, 2, 3, 4, 5])).toEqual(3); - }); + [ + { input: [1, 2, 3], expected: 2 }, + { input: [1, 2, 3, 4, 5], expected: 3 }, + { input: [1, 2, 3, 4], expected: 2.5 }, + { input: [1, 2, 3, 4, 5, 6], expected: 3.5 }, + ].forEach(({ input, expected }) => + it(`returns the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + ); - it("returns the average of middle values for even length array", () => { - expect(calculateMedian([1, 2, 3, 4])).toEqual(2.5); - expect(calculateMedian([1, 2, 3, 4, 5, 6])).toEqual(3.5); - }); + [ + { input: [3, 1, 2], expected: 2 }, + { input: [5, 1, 3, 4, 2], expected: 3 }, + { input: [4, 2, 1, 3], expected: 2.5 }, + { input: [6, 1, 5, 3, 2, 4], expected: 3.5 }, + ].forEach(({ input, expected }) => + it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + ); - it("doesn't modify the input", () => { + it("doesn't modify the input array [1, 2, 3]", () => { const list = [1, 2, 3]; calculateMedian(list); - expect(list).toEqual([1, 2, 3]); }); }); From 7e1c7e34cc589c71c4ece53a7ab2de7a7980f094 Mon Sep 17 00:00:00 2001 From: Andrei Navumau Date: Sat, 15 Mar 2025 15:46:20 -0400 Subject: [PATCH 2/4] Add tests to check for errors and mixed arrays (advanced implementation of median) --- Sprint-1/fix/median.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 05fa35f4a..6f1ee4114 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -30,4 +30,19 @@ describe("calculateMedian", () => { calculateMedian(list); expect(list).toEqual([1, 2, 3]); }); + + [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => + it(`throws an error for non-numeric array (${val})`, () => expect(() => calculateMedian(val)).toThrow()) + ); + + [ + { input: [1, 2, "3", null, undefined, 4], expected: 2 }, + { input: ["apple", 1, 2, 3, "banana", 4], expected: 2.5 }, + { input: [1, "2", 3, "4", 5], expected: 3 }, + { input: [1, "apple", 2, null, 3, undefined, 4], expected: 2.5 }, + { input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 }, + { input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 }, + ].forEach(({ input, expected }) => + it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + ); }); From a6fd7064504d9f4856c9116ce247d0ce41d879da Mon Sep 17 00:00:00 2001 From: Andrei Navumau Date: Fri, 21 Mar 2025 13:25:12 -0400 Subject: [PATCH 3/4] Create two vesions of calculate median function: with throw error and with return null --- Sprint-1/fix/median.js | 31 +++++++++++++++++++++-- Sprint-1/fix/median.test.js | 49 ++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index aef3f27af..ad7896ab1 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -16,9 +16,36 @@ // 2 - We actually don't need .splice() or any other method to find a median. // 3 - We must sort the array before we search for the median. // 4 - We should check if the 'list' parameter actually has numbers, otherwise try to filter -// out all non-numeric values or throw an error if there are no numeric values. +// out all non-numeric values and throw an error or return null if there are no numeric values. + + +// Example of a function calculating median and returning null in case no numeric values provided. function calculateMedian(list) { + if (!Array.isArray(list)) { + return null; + } + const onlyNumberList = list.filter(item => typeof item === 'number' && !isNaN(item)); + + if (!onlyNumberList.length) { + return null; + } else { + const sortedList = onlyNumberList.sort((current, next) => current - next); + const indexNearMiddleOfArray = Math.floor(sortedList.length / 2); + if (sortedList.length % 2 === 0) { + return (sortedList[indexNearMiddleOfArray - 1] + sortedList[indexNearMiddleOfArray]) / 2; + } else { + return sortedList[indexNearMiddleOfArray]; + } + } +} + +// Example of a function calculating median and throwing error in case no numeric values provided. + +function calculateMedianImproved(list) { + if (!Array.isArray(list)) { + throw new Error('You provided not an array.'); + } const onlyNumberList = list.filter(item => typeof item === 'number' && !isNaN(item)); if (!onlyNumberList.length) { @@ -34,4 +61,4 @@ function calculateMedian(list) { } } -module.exports = calculateMedian; +module.exports = { calculateMedian, calculateMedianImproved }; diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 6f1ee4114..edd3c1b37 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -4,7 +4,50 @@ // passing all the tests... // Fix the implementation of calculateMedian so it passes all tests -const calculateMedian = require("./median.js"); +const { calculateMedian, calculateMedianImproved } = require("./median.js"); + +if (calculateMedianImproved) { + describe("calculateMedianImproved", () => { + [ + { input: [1, 2, 3], expected: 2 }, + { input: [1, 2, 3, 4, 5], expected: 3 }, + { input: [1, 2, 3, 4], expected: 2.5 }, + { input: [1, 2, 3, 4, 5, 6], expected: 3.5 }, + ].forEach(({ input, expected }) => + it(`returns the median for [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) + ); + + [ + { input: [3, 1, 2], expected: 2 }, + { input: [5, 1, 3, 4, 2], expected: 3 }, + { input: [4, 2, 1, 3], expected: 2.5 }, + { input: [6, 1, 5, 3, 2, 4], expected: 3.5 }, + ].forEach(({ input, expected }) => + it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) + ); + + it("doesn't modify the input array [1, 2, 3]", () => { + const list = [1, 2, 3]; + calculateMedianImproved(list); + expect(list).toEqual([1, 2, 3]); + }); + + [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => + it(`throws an error for non-numeric array (${val})`, () => expect(() => calculateMedianImproved(val)).toThrow()) + ); + + [ + { input: [1, 2, "3", null, undefined, 4], expected: 2 }, + { input: ["apple", 1, 2, 3, "banana", 4], expected: 2.5 }, + { input: [1, "2", 3, "4", 5], expected: 3 }, + { input: [1, "apple", 2, null, 3, undefined, 4], expected: 2.5 }, + { input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 }, + { input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 }, + ].forEach(({ input, expected }) => + it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) + ); + }); +} describe("calculateMedian", () => { [ @@ -32,7 +75,7 @@ describe("calculateMedian", () => { }); [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => - it(`throws an error for non-numeric array (${val})`, () => expect(() => calculateMedian(val)).toThrow()) + it(`returns null for non-numeric array (${val})`, () => expect(calculateMedian(val)).toBe(null)) ); [ @@ -45,4 +88,4 @@ describe("calculateMedian", () => { ].forEach(({ input, expected }) => it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) ); -}); +}); \ No newline at end of file From 504c533fe1b30ad300c554c2f4f82980c0e266c1 Mon Sep 17 00:00:00 2001 From: Andrei Navumau Date: Fri, 21 Mar 2025 13:31:24 -0400 Subject: [PATCH 4/4] Remove calculate median with throwing error and related tests --- Sprint-1/fix/median.js | 23 +------------------ Sprint-1/fix/median.test.js | 45 +------------------------------------ 2 files changed, 2 insertions(+), 66 deletions(-) diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index ad7896ab1..6611ca3a4 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -40,25 +40,4 @@ function calculateMedian(list) { } } -// Example of a function calculating median and throwing error in case no numeric values provided. - -function calculateMedianImproved(list) { - if (!Array.isArray(list)) { - throw new Error('You provided not an array.'); - } - const onlyNumberList = list.filter(item => typeof item === 'number' && !isNaN(item)); - - if (!onlyNumberList.length) { - throw new Error('You provided a list without numbers.'); - } else { - const sortedList = onlyNumberList.sort((current, next) => current - next); - const indexNearMiddleOfArray = Math.floor(sortedList.length / 2); - if (sortedList.length % 2 === 0) { - return (sortedList[indexNearMiddleOfArray - 1] + sortedList[indexNearMiddleOfArray]) / 2; - } else { - return sortedList[indexNearMiddleOfArray]; - } - } -} - -module.exports = { calculateMedian, calculateMedianImproved }; +module.exports = calculateMedian; diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index edd3c1b37..16643a163 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -4,50 +4,7 @@ // passing all the tests... // Fix the implementation of calculateMedian so it passes all tests -const { calculateMedian, calculateMedianImproved } = require("./median.js"); - -if (calculateMedianImproved) { - describe("calculateMedianImproved", () => { - [ - { input: [1, 2, 3], expected: 2 }, - { input: [1, 2, 3, 4, 5], expected: 3 }, - { input: [1, 2, 3, 4], expected: 2.5 }, - { input: [1, 2, 3, 4, 5, 6], expected: 3.5 }, - ].forEach(({ input, expected }) => - it(`returns the median for [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) - ); - - [ - { input: [3, 1, 2], expected: 2 }, - { input: [5, 1, 3, 4, 2], expected: 3 }, - { input: [4, 2, 1, 3], expected: 2.5 }, - { input: [6, 1, 5, 3, 2, 4], expected: 3.5 }, - ].forEach(({ input, expected }) => - it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) - ); - - it("doesn't modify the input array [1, 2, 3]", () => { - const list = [1, 2, 3]; - calculateMedianImproved(list); - expect(list).toEqual([1, 2, 3]); - }); - - [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => - it(`throws an error for non-numeric array (${val})`, () => expect(() => calculateMedianImproved(val)).toThrow()) - ); - - [ - { input: [1, 2, "3", null, undefined, 4], expected: 2 }, - { input: ["apple", 1, 2, 3, "banana", 4], expected: 2.5 }, - { input: [1, "2", 3, "4", 5], expected: 3 }, - { input: [1, "apple", 2, null, 3, undefined, 4], expected: 2.5 }, - { input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 }, - { input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 }, - ].forEach(({ input, expected }) => - it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedianImproved(input)).toEqual(expected)) - ); - }); -} +const calculateMedian = require("./median.js"); describe("calculateMedian", () => { [