diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index b22590bc6..b27f16bc3 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -6,8 +6,17 @@ // or 'list' has mixed values (the function is expected to sort only numbers). function calculateMedian(list) { - const middleIndex = Math.floor(list.length / 2); - const median = list.splice(middleIndex, 1)[0]; + if (!Array.isArray(list)) return null; + const num = list.filter((l) => typeof l === "number").sort((a, b) => a - b); + if (num.length < 1) return null; + if (num.length === 1) return num[0]; + + const middleIndex = Math.floor(num.length / 2); + + if (num.length % 2 === 0) { + return (num[middleIndex] + num[middleIndex - 1]) / 2; + } + const median = num[middleIndex]; return median; } diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 21da654d7..b48b9f7ab 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -8,15 +8,24 @@ const calculateMedian = require("./median.js"); describe("calculateMedian", () => { [ + { input: [1.5, 2.5, 3.5], expected: 2.5 }, + { input: [-2, -4, -6, -10], expected: -5 }, + { input: [3, 3, 3, 3, 3], expected: 3 }, + { input: [1, 3], expected: 2 }, + { input: [1], expected: 1 }, { 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 median for [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); [ + { input: [-5, -1, -3], expected: -3 }, + { input: [2, 2, 2, 2], expected: 2 }, + { input: [8, 4], expected: 6 }, { input: [3, 1, 2], expected: 2 }, { input: [5, 1, 3, 4, 2], expected: 3 }, { input: [4, 2, 1, 3], expected: 2.5 }, @@ -24,7 +33,8 @@ describe("calculateMedian", () => { { input: [110, 20, 0], expected: 20 }, { input: [6, -2, 2, 12, 14], expected: 6 }, ].forEach(({ input, expected }) => - it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + it(`returns the correct median for unsorted array [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); it("doesn't modify the input array [3, 1, 2]", () => { @@ -33,11 +43,21 @@ describe("calculateMedian", () => { expect(list).toEqual([3, 1, 2]); }); - [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => - it(`returns null for non-numeric array (${val})`, () => expect(calculateMedian(val)).toBe(null)) + [ + "not an array", + 123, + null, + undefined, + {}, + [], + ["apple", null, undefined], + ].forEach((val) => + it(`returns null for non-numeric array (${val})`, () => + expect(calculateMedian(val)).toBe(null)) ); [ + { input: ["a", null, 5, undefined], expected: 5 }, { 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 }, @@ -45,6 +65,7 @@ describe("calculateMedian", () => { { 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)) + it(`filters out non-numeric values and calculates the median for [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); }); diff --git a/Sprint-1/implement/dedupe.js b/Sprint-1/implement/dedupe.js index 781e8718a..e40264004 100644 --- a/Sprint-1/implement/dedupe.js +++ b/Sprint-1/implement/dedupe.js @@ -1 +1,22 @@ -function dedupe() {} +function dedupe(input) { + if (!Array.isArray(input)) { + return null; + } + + if (input.length === 0) { + return []; + } + + const newArray = []; + + for (let i = 0; i < input.length; i++) { + const element = input[i]; + + if (!newArray.includes(element)) { + newArray.push(element); + } + } + return newArray; +} + +module.exports = dedupe; diff --git a/Sprint-1/implement/dedupe.test.js b/Sprint-1/implement/dedupe.test.js index 23e0f8638..25d718b1e 100644 --- a/Sprint-1/implement/dedupe.test.js +++ b/Sprint-1/implement/dedupe.test.js @@ -16,7 +16,6 @@ E.g. dedupe([1, 2, 1]) target output: [1, 2] // Given an empty array // When passed to the dedupe function // Then it should return an empty array -test.todo("given an empty array, it returns an empty array"); // Given an array with no duplicates // When passed to the dedupe function @@ -25,3 +24,33 @@ test.todo("given an empty array, it returns an empty array"); // Given an array with strings or numbers // When passed to the dedupe function // Then it should remove the duplicate values, preserving the first occurence of each element + +describe("dedupe", () => { + it("returns an empty array if passed an empty array", () => + expect(dedupe([])).toEqual([])); + + [ + { input: [1, 2, 3], expected: [1, 2, 3] }, + { + input: [4542543, 65756756, 433254], + expected: [4542543, 65756756, 433254], + }, + ].forEach(({ input, expected }) => + it( + "returns a copy of original array when passed array with no duplicates ", + () => expect(dedupe(input)).toEqual(expected), + expect(dedupe(input)).not.toBe(input) + ) + ); + + [ + { input: [1, 2, 3, "apple", 3, 2, {}], expected: [1, 2, 3, "apple", {}] }, + { + input: [4542543, undefined, 4542543, 4542543, null, [], null], + expected: [4542543, undefined, null, []], + }, + ].forEach(({ input, expected }) => + it("returns array wit unique values in their first occurrence index when passed an array with numbers and non-number values ", () => + expect(dedupe(input)).toEqual(expected)) + ); +}); diff --git a/Sprint-1/implement/max.js b/Sprint-1/implement/max.js index 6dd76378e..86e2deca5 100644 --- a/Sprint-1/implement/max.js +++ b/Sprint-1/implement/max.js @@ -1,4 +1,9 @@ function findMax(elements) { + const numberElements = elements.filter( + (el) => typeof el === "number" && !Number.isNaN(el) + ); + if (numberElements.length === 0) return -Infinity; + return Math.max(...numberElements); } module.exports = findMax; diff --git a/Sprint-1/implement/max.test.js b/Sprint-1/implement/max.test.js index 82f18fd88..2e825a7cb 100644 --- a/Sprint-1/implement/max.test.js +++ b/Sprint-1/implement/max.test.js @@ -16,28 +16,94 @@ const findMax = require("./max.js"); // When passed to the max function // Then it should return -Infinity // Delete this test.todo and replace it with a test. -test.todo("given an empty array, returns -Infinity"); -// Given an array with one number -// When passed to the max function -// Then it should return that number +describe("max()", () => { + it("returns -Infinity for empty array", () => + expect(findMax([])).toBe(-Infinity)); -// Given an array with both positive and negative numbers -// When passed to the max function -// Then it should return the largest number overall + // Given an array with one number + // When passed to the max function + // Then it should return that number -// Given an array with just negative numbers -// When passed to the max function -// Then it should return the closest one to zero + [ + { input: [43], expected: 43 }, + { input: [342], expected: 342 }, + { input: [65455453], expected: 65455453 }, + ].forEach(({ input, expected }) => + it("returns the only number in array with one number", () => + expect(findMax(input)).toBe(expected)) + ); -// Given an array with decimal numbers -// When passed to the max function -// Then it should return the largest decimal number + // Given an array with both positive and negative numbers + // When passed to the max function + // Then it should return the largest number overall -// Given an array with non-number values -// When passed to the max function -// Then it should return the max and ignore non-numeric values + [ + { input: [43, -4], expected: 43 }, + { input: [342, -45, -768, 23], expected: 342 }, + { input: [65455453, -54666, -4566, 6565], expected: 65455453 }, + ].forEach(({ input, expected }) => + it("returns the largest number in array containing negative numbers", () => + expect(findMax(input)).toBe(expected)) + ); -// Given an array with only non-number values -// When passed to the max function -// Then it should return the least surprising value given how it behaves for all other inputs + // Given an array with just negative numbers + // When passed to the max function + // Then it should return the closest one to zero + + [ + { input: [-43, -4], expected: -4 }, + { input: [-342, -45, -768, -23], expected: -23 }, + { input: [-65455453, -54666, -4566, -6565], expected: -4566 }, + ].forEach(({ input, expected }) => + it("returns closes number to zero in an array with only negative numbers", () => + expect(findMax(input)).toBe(expected)) + ); + + // Given an array with decimal numbers + // When passed to the max function + // Then it should return the largest decimal number + + [ + { input: [43.32, -4.1], expected: 43.32 }, + { input: [342.54, -45.12, -768.76, 23.99], expected: 342.54 }, + { + input: [65455453.4533, -54666.222, -4566.322, 6565.43], + expected: 65455453.4533, + }, + ].forEach(({ input, expected }) => + it("returns the largest decimal number in an array with numbers", () => + expect(findMax(input)).toBe(expected)) + ); + + // Given an array with non-number values + // When passed to the max function + // Then it should return the max and ignore non-numeric values + + [ + { input: [0, NaN, 1], expected: 1 }, + { input: [1, 2, "3", null, undefined, NaN, 4], expected: 4 }, + { input: ["apple", 1, 2, 34, "banana", 4], expected: 34 }, + { input: [1, "2", 3, "4", 5], expected: 5 }, + { input: [1, "apple", 2, null, 3, undefined, 4], expected: 4 }, + { input: [3, "apple", 1, null, 2, undefined, 4, 54], expected: 54 }, + { input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 5 }, + ].forEach(({ input, expected }) => + it("returns max of numbers in an array containing non-numeric values", () => + expect(findMax(input)).toEqual(expected)) + ); + + // Given an array with only non-number values + // When passed to the max function + // Then it should return the least surprising value given how it behaves for all other inputs + + [ + ["not an array", "3", null, undefined], + ["apple", "banana"], + ["apple", null, undefined], + ["banana", {}], + ].forEach((input) => + it("returns -Infinity in array with only non-numeric values", () => + expect(findMax(input)).toBe(-Infinity)) + ); +}); diff --git a/Sprint-1/implement/sum.js b/Sprint-1/implement/sum.js index 9062aafe3..6fa7fa829 100644 --- a/Sprint-1/implement/sum.js +++ b/Sprint-1/implement/sum.js @@ -1,4 +1,22 @@ function sum(elements) { + if (!Array.isArray(elements)) { + return null; + } + // Check if array is empty + if (elements.length === 0) { + return 0; + } + // Filter only numeric values + const numericElements = elements.filter((item) => typeof item === "number"); + if (numericElements.length === 0) { + return -Infinity; + } + // Calculate the sum of numeric values + let total = 0; + for (let i = 0; i < numericElements.length; i++) { + total += numericElements[i]; + } + return total; } module.exports = sum; diff --git a/Sprint-1/implement/sum.test.js b/Sprint-1/implement/sum.test.js index dd0a090ca..d30526d43 100644 --- a/Sprint-1/implement/sum.test.js +++ b/Sprint-1/implement/sum.test.js @@ -13,7 +13,6 @@ const sum = require("./sum.js"); // Given an empty array // When passed to the sum function // Then it should return 0 -test.todo("given an empty array, returns 0") // Given an array with just one number // When passed to the sum function @@ -34,3 +33,11 @@ test.todo("given an empty array, returns 0") // Given an array with only non-number values // When passed to the sum function // Then it should return the least surprising value given how it behaves for all other inputs + +test(`Should return the correct sum of the numerical elements of an array`, () => { + expect(sum(["apple", "banana", 1, 10])).toEqual(11); + expect(sum([1, -1, -100])).toEqual(-100); + expect(sum([-10, -20, -3, -4])).toEqual(-37); + expect(sum([1.5, 10.5, 0.5])).toBeCloseTo(12.5); + expect(sum(["apple", "banana", "cherry"])).toEqual(-Infinity); +}); diff --git a/Sprint-1/package-lock.json b/Sprint-1/package-lock.json index 83e427d0b..b52480af5 100644 --- a/Sprint-1/package-lock.json +++ b/Sprint-1/package-lock.json @@ -56,6 +56,7 @@ "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.25.7", @@ -1368,6 +1369,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001663", "electron-to-chromium": "^1.5.28", diff --git a/Sprint-1/refactor/includes.js b/Sprint-1/refactor/includes.js index 29dad81f0..8c9ae2e66 100644 --- a/Sprint-1/refactor/includes.js +++ b/Sprint-1/refactor/includes.js @@ -1,8 +1,7 @@ // Refactor the implementation of includes to use a for...of loop function includes(list, target) { - for (let index = 0; index < list.length; index++) { - const element = list[index]; + for (const element of list) { if (element === target) { return true; }