diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index b22590bc6..995cc9be7 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -6,8 +6,30 @@ // or 'list' has mixed values (the function is expected to sort only numbers). function calculateMedian(list) { + // check if input is an array + if (!Array.isArray(list)) return null; + + // filter out non-numeric values + list = list.filter((item) => typeof item === "number"); + + // if the array is empty after filtering, return null + if (list.length === 0) return null; + + // sort the array + list = [...list].sort((a, b) => a - b); + + // for the case of even length arrays + if (list.length % 2 === 0) { + const middleIndex1 = list.length / 2; + const middleIndex2 = middleIndex1 - 1; + const median = (list[middleIndex1] + list[middleIndex2]) / 2; + return median; + } + + // for the case of odd length arrays const middleIndex = Math.floor(list.length / 2); const median = list.splice(middleIndex, 1)[0]; + return median; } diff --git a/Sprint-1/implement/dedupe.js b/Sprint-1/implement/dedupe.js index 781e8718a..b84408568 100644 --- a/Sprint-1/implement/dedupe.js +++ b/Sprint-1/implement/dedupe.js @@ -1 +1,13 @@ -function dedupe() {} +function dedupe(arr) { + // Ensure arr is an array + if (!Array.isArray(arr)) { + throw new Error("Input must be an array"); + } + + // return [] if arr is [] + if (arr.length === 0) return []; + + return [...new Set(arr)]; +} + +module.exports = dedupe; diff --git a/Sprint-1/implement/dedupe.test.js b/Sprint-1/implement/dedupe.test.js index 23e0f8638..e20443e64 100644 --- a/Sprint-1/implement/dedupe.test.js +++ b/Sprint-1/implement/dedupe.test.js @@ -13,15 +13,62 @@ E.g. dedupe([1, 2, 1]) target output: [1, 2] // Acceptance Criteria: +// Making sure input is an array +// When the input is not array, throw an error +test("should return an error when the input is not an array", () => { + const errorMessage = "Input must be an array"; + expect(() => dedupe("not an array")).toThrow(errorMessage); + expect(() => dedupe(123)).toThrow(errorMessage); + expect(() => dedupe({})).toThrow(errorMessage); + expect(() => dedupe(null)).toThrow(errorMessage); + expect(() => dedupe(undefined)).toThrow(errorMessage); + expect(() => dedupe(true)).toThrow(errorMessage); +}); + // 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"); +test("given an empty array, it returns an empty array", () => { + expect(dedupe([])).toEqual([]); +}); // Given an array with no duplicates // When passed to the dedupe function // Then it should return a copy of the original array +test("given an array with no duplicates, it returns the original array", () => { + expect(dedupe(["a", "b", "c"])).toEqual(["a", "b", "c"]); + expect(dedupe([1, 2, 3])).toEqual([1, 2, 3]); + expect(dedupe([{ key1: "a" }, { key2: "b" }, { key3: "c" }])).toEqual([ + { key1: "a" }, + { key2: "b" }, + { key3: "c" }, + ]); + expect(dedupe([true, false])).toEqual([true, false]); +}); // 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 +// Then it should remove the duplicate values, preserving the first occurrence of each element +test("given an array with strings or numbers, it returns first occurrence of each element", () => { + expect(dedupe(["a", "b", "c", "a", "b", "c", "d"])).toEqual([ + "a", + "b", + "c", + "d", + ]); + expect(dedupe([1, 2, 2, 3, 3, 4, 1, 5])).toEqual([1, 2, 3, 4, 5]); +}); + +// Given an array with mixed strings and numbers +// When passed to the dedupe function +// Then it should remove the duplicate values, preserving the first occurrence of each element +test("given an array with mixed strings and numbers, it returns first occurrence of each element", () => { + expect(dedupe([1, 1, 2, "x", "x", "y", "z", 2, 3, 3, "z"])).toEqual([ + 1, + 2, + "x", + "y", + "z", + 3, + ]); +}); diff --git a/Sprint-1/implement/max.js b/Sprint-1/implement/max.js index 6dd76378e..6b0e6931a 100644 --- a/Sprint-1/implement/max.js +++ b/Sprint-1/implement/max.js @@ -1,4 +1,20 @@ function findMax(elements) { + // ensure elements is an array + if (!Array.isArray(elements)) { + throw new Error("Input must be an array"); + } + + // filter out non-numeric values + elements = elements.filter((element) => typeof element === "number"); + + if (elements.length === 0) { + return -Infinity; + } + if (elements.length === 1) { + return elements[0]; + } + + return Math.max(...elements); } module.exports = findMax; diff --git a/Sprint-1/implement/max.test.js b/Sprint-1/implement/max.test.js index 82f18fd88..e63d143c3 100644 --- a/Sprint-1/implement/max.test.js +++ b/Sprint-1/implement/max.test.js @@ -12,32 +12,63 @@ We have set things up already so that this file can see your function from the o const findMax = require("./max.js"); +// Making sure the elements is an array +test("throws an error if input is not an array", () => { + const errorMessage = "Input must be an array"; + expect(() => findMax("not an array")).toThrow(errorMessage); + expect(() => findMax(123)).toThrow(errorMessage); + expect(() => findMax({})).toThrow(errorMessage); + expect(() => findMax(null)).toThrow(errorMessage); + expect(() => findMax(undefined)).toThrow(errorMessage); + expect(() => findMax(true)).toThrow(errorMessage); +}); + // Given an empty array // 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"); +test("given an empty array, returns -Infinity", () => { + expect(findMax([])).toBe(-Infinity); +}); // Given an array with one number // When passed to the max function // Then it should return that number +test("given an array with one number, returns that number", () => { + expect(findMax([42])).toBe(42); +}); // Given an array with both positive and negative numbers // When passed to the max function // Then it should return the largest number overall +test("given an array with both positive and negative numbers, returns the largest number overall", () => { + expect(findMax([-10, -20, 0, 10, 20])).toBe(20); +}); // Given an array with just negative numbers // When passed to the max function // Then it should return the closest one to zero +test("given an array with just negative numbers, returns the closest one to zero", () => { + expect(findMax([-10, -20, -5, -15])).toBe(-5); +}); // Given an array with decimal numbers // When passed to the max function // Then it should return the largest decimal number +test("given an array with decimal numbers, returns the largest decimal number", () => { + expect(findMax([1.5, 2.3, 0.7, 2.9])).toBe(2.9); +}); // Given an array with non-number values // When passed to the max function // Then it should return the max and ignore non-numeric values +test("given an array with non-number values, returns the max and ignores non-numeric values", () => { + expect(findMax([10, "hello", 20, null, 15, undefined, 5])).toBe(20); +}); // 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 +test("given an array with only non-number values, returns -Infinity", () => { + expect(findMax(["hello", null, undefined, {}, []])).toBe(-Infinity); +}); diff --git a/Sprint-1/implement/sum.js b/Sprint-1/implement/sum.js index 9062aafe3..c52153cbe 100644 --- a/Sprint-1/implement/sum.js +++ b/Sprint-1/implement/sum.js @@ -1,4 +1,18 @@ function sum(elements) { + // Ensure the input is an array + if (!Array.isArray(elements)) { + throw new Error("Input must be an array"); + } + + // filter out non-numerical values + elements = elements.filter((element) => typeof element === "number"); + + // if the array is empty, return 0 + if (elements.length === 0) { + return 0; + } + + return elements.reduce((acc, num) => acc + num, 0); } module.exports = sum; diff --git a/Sprint-1/implement/sum.test.js b/Sprint-1/implement/sum.test.js index dd0a090ca..c98180aa3 100644 --- a/Sprint-1/implement/sum.test.js +++ b/Sprint-1/implement/sum.test.js @@ -10,27 +10,65 @@ const sum = require("./sum.js"); // Acceptance Criteria: +// Ensure the input is an array +// If the input is not an array, throw an error +test("throws an error if the input is not an array", () => { + const errorMessage = "Input must be an array"; + expect(() => sum(123)).toThrow(errorMessage); + expect(() => sum("not an array")).toThrow(errorMessage); + expect(() => sum({ key: "value" })).toThrow(errorMessage); + expect(() => sum(null)).toThrow(errorMessage); + expect(() => sum(undefined)).toThrow(errorMessage); + expect(() => sum(true)).toThrow(errorMessage); +}); + // Given an empty array // When passed to the sum function // Then it should return 0 -test.todo("given an empty array, returns 0") +test("given an empty array, returns 0", () => { + expect(sum([])).toBe(0); +}); // Given an array with just one number // When passed to the sum function // Then it should return that number +test("given an array with one number, returns that number", () => { + expect(sum([42])).toBe(42); + expect(sum([-7])).toBe(-7); + expect(sum([0])).toBe(0); +}); // Given an array containing negative numbers // When passed to the sum function // Then it should still return the correct total sum +test("given an array with negative numbers, returns the correct sum", () => { + expect(sum([10, -5, 15])).toBe(20); + expect(sum([-10, -20, -30])).toBe(-60); + expect(sum([5, -5, 0])).toBe(0); +}); // Given an array with decimal/float numbers // When passed to the sum function // Then it should return the correct total sum +test("given an array with decimal numbers, returns the correct sum", () => { + expect(sum([1.5, 2.5, 3.0])).toBeCloseTo(7.0); + expect(sum([-1.5, -2.5, -3.0])).toBeCloseTo(-7.0); + expect(sum([0.1, 0.2, 0.3])).toBeCloseTo(0.6); +}); // Given an array containing non-number values // When passed to the sum function // Then it should ignore the non-numerical values and return the sum of the numerical elements +test("given an array with non-number values, ignores them and returns the sum of numbers", () => { + expect(sum([10, "hello", 20, null, 30, undefined])).toBe(60); + expect(sum(["hey", 10, "hi", 60, 10])).toBe(80); + expect(sum([true, false, 5, 15])).toBe(20); +}); // 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("given an array with only non-number values, returns 0", () => { + expect(sum(["hello", null, undefined, true, false])).toBe(0); + expect(sum([{}, [], "string", null])).toBe(0); +}); diff --git a/Sprint-1/refactor/includes.js b/Sprint-1/refactor/includes.js index 29dad81f0..916bcae13 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 (element of list) { if (element === target) { return true; } diff --git a/Sprint-1/stretch/aoc-2018-day1/solution.js b/Sprint-1/stretch/aoc-2018-day1/solution.js index e69de29bb..20ae80a37 100644 --- a/Sprint-1/stretch/aoc-2018-day1/solution.js +++ b/Sprint-1/stretch/aoc-2018-day1/solution.js @@ -0,0 +1,22 @@ +const fs = require("fs"); +const path = require("path"); + +function solution() { + // set the file path + const filePath = path.join(__dirname, "input.txt"); + + // read the file + let frequencies = fs.readFileSync(filePath, "utf-8"); + + // split the numbers by next line and covert them into Number + frequencies = frequencies.split("\n").map((num) => Number(num)); + + // reduce to get the total = 529 + const total = frequencies.reduce((acc, num) => acc + num, 0); + + return total; +} + +console.log(solution()); + +module.exports = solution;