diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index 5c5b796e1..8bf6aa764 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -6,9 +6,25 @@ // or contains values that aren't numbers (the function is expected to throw - see the tests). function calculateMedian(list) { - const middleIndex = Math.floor(list.length / 2); - const median = list.splice(middleIndex, 1)[0]; - return median; + if (!Array.isArray(list)) { + throw new Error("calculateMedian requires an array of numbers"); + } + + if (list.length === 0) { + throw new Error("calculateMedian requires a non-empty array"); + } + + for (const item of list) { + if (typeof item !== "number") { + throw new Error("calculateMedian requires an array of numbers"); + } + } + const sorted = [...list].sort((a, b) => a - b); + const middleIndex = Math.floor(sorted.length / 2); + if (sorted.length % 2 === 0) { + return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2; + } + return sorted[middleIndex]; } module.exports = calculateMedian; diff --git a/Sprint-1/implement/dedupe.js b/Sprint-1/implement/dedupe.js index 781e8718a..2ec3c6352 100644 --- a/Sprint-1/implement/dedupe.js +++ b/Sprint-1/implement/dedupe.js @@ -1 +1,16 @@ -function dedupe() {} +function dedupe(list) { + const elements = []; + + if (list.length === 0) { + return []; + } + + for (const item of list) { + if (!elements.includes(item)) { + elements.push(item); + } + } + return elements; +} + +module.exports = dedupe; diff --git a/Sprint-1/implement/dedupe.test.js b/Sprint-1/implement/dedupe.test.js index d7c8e3d8e..094e7dc0c 100644 --- a/Sprint-1/implement/dedupe.test.js +++ b/Sprint-1/implement/dedupe.test.js @@ -16,13 +16,27 @@ E.g. dedupe([1, 2, 1]) returns [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"); +test("given an empty array, it returns an empty array", () => { + const list = []; + const result = dedupe(list); + expect(dedupe(list)).toEqual(result); +}); // 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 a copy of the original array", () => { + const list = ["a", "b", "c"]; + const result = dedupe(list); + expect(dedupe(list)).toEqual(result); +}); // Given an array of strings or numbers // When passed to the dedupe function -// Then it should return a new array with duplicates removed while preserving the +// Then it should return a new array with duplicates removed while preserving the // first occurrence of each element from the original array. +test("given an array, it returns an array with duplicates removed and its original occurrence", () => { + const list = [3, 1, 2]; + const result = dedupe(list); + expect(dedupe(list)).toEqual(result); +}); diff --git a/Sprint-1/implement/describe-median.js b/Sprint-1/implement/describe-median.js index 3381cfc0a..e81890647 100644 --- a/Sprint-1/implement/describe-median.js +++ b/Sprint-1/implement/describe-median.js @@ -20,6 +20,12 @@ function calculateMedian(list) { } // Implement this function. See describe-median.test.js for the acceptance criteria. -function describeMedian(list) {} +function describeMedian(list) { + try { + return `The median is ${calculateMedian(list)}`; + } catch (error) { + return `Could not calculate a median: calculateMedian requires a non-empty array: ${error.message}`; + } +} module.exports = describeMedian; diff --git a/Sprint-1/implement/describe-median.test.js b/Sprint-1/implement/describe-median.test.js index e7d18a264..49427757d 100644 --- a/Sprint-1/implement/describe-median.test.js +++ b/Sprint-1/implement/describe-median.test.js @@ -15,18 +15,33 @@ message, so the caller can see what went wrong. const describeMedian = require("./describe-median.js"); + // Acceptance criteria: // Given an array of numbers // When passed to describeMedian // Then it should return "The median is " followed by the median // Delete this test.todo and replace it with a test. -test.todo('given [1, 2, 3], returns "The median is 2"'); +test("given [1, 2, 3], returns The median is 2", () => { + const list = [1, 2, 3]; + const result = describeMedian(list); + expect(describeMedian(list)).toEqual(result); +}); // Given an empty array // When passed to describeMedian // Then it should return "Could not calculate a median: calculateMedian requires a non-empty array" +test("given an empty array [], returns Could not calculate a median", () => { + const list = []; + const result = describeMedian(list); + expect(describeMedian(list)).toEqual(result); +}); // Given something that isn't an array of numbers, e.g. "banana" // When passed to describeMedian // Then it should return "Could not calculate a median: calculateMedian requires an array of numbers" +test("given a non-array , returns Could not calculate a median", () => { + const list = []; + const result = describeMedian(list); + expect(describeMedian(list)).toEqual(result); +}); \ No newline at end of file diff --git a/Sprint-1/implement/max.js b/Sprint-1/implement/max.js index 6dd76378e..efee75da5 100644 --- a/Sprint-1/implement/max.js +++ b/Sprint-1/implement/max.js @@ -1,4 +1,18 @@ function findMax(elements) { + if (!Array.isArray(elements)) { + throw new Error("findMax requires an array of numbers"); + } + + for (const element of elements) { + if (typeof element !== "number") { + throw new Error("findMax requires an array of numbers"); + } + + if (!elements.length === 1) { + return element; + } + } + return Math.max(...elements); } module.exports = findMax; diff --git a/Sprint-1/implement/max.test.js b/Sprint-1/implement/max.test.js index ff3fbb5e5..2fbfa0139 100644 --- a/Sprint-1/implement/max.test.js +++ b/Sprint-1/implement/max.test.js @@ -16,28 +16,60 @@ 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"); +test("given an empty array, returns -Infinity", () => { + expect(findMax([])).toEqual(-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", () => { + const list = [1]; + const result = findMax(list); + expect(result).toEqual(1); +}); // 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 positive and negative numbers, returns the largest number", () => { + const list = [1, -9, 7, -5]; + const result = findMax(list); + expect(result).toEqual(7); +}); // 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 negative numbers, returns closest one to zero", () => { + const list = [-1, -9, -7, -5]; + const result = findMax(list); + expect(result).toEqual(-1); +}); // 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", () => { + const list = [1.1, 0.9, 4.7, 1.5]; + const result = findMax(list); + expect(result).toEqual(4.7); +}); // Given an array containing a value that isn't a number // When passed to the max function // Then it should throw Error("findMax requires an array of numbers") +test("given an array with non-numbers, returns, findMax requires an array of numbers", () => { + expect(() => findMax(["a", "l", "k"])).toThrow( + new Error("findMax requires an array of numbers") + ); +}); // Given something that isn't an array at all, such as "hey", 42 or no argument // When passed to the max function // Then it should throw Error("findMax requires an array of numbers") +test("given a non-array, returns, findMax requires an array of numbers", () => { + expect(() => findMax("a", "", 7, "kilo")).toThrow( + new Error("findMax requires an array of numbers") + ); +}); \ No newline at end of file diff --git a/Sprint-1/implement/mean.js b/Sprint-1/implement/mean.js index 36909ea1f..fbbecbddd 100644 --- a/Sprint-1/implement/mean.js +++ b/Sprint-1/implement/mean.js @@ -1,3 +1,18 @@ -function calculateMean(list) {} +function calculateMean(list) { + if (!Array.isArray(list)) { + throw new Error("calculateMean requires an array of numbers"); + } + if (list.length === 0) { + throw new Error("calculateMean requires a non-empty array"); + } + let total = 0; + for (const item of list) { + if (typeof item !== "number") { + throw new Error("calculateMean requires an array of numbers"); + } + total = total + item; + } + return Number(total.toFixed(2)) / list.length; +} module.exports = calculateMean; diff --git a/Sprint-1/implement/mean.test.js b/Sprint-1/implement/mean.test.js index 847b88676..ee7e93f8f 100644 --- a/Sprint-1/implement/mean.test.js +++ b/Sprint-1/implement/mean.test.js @@ -23,28 +23,66 @@ const calculateMean = require("./mean.js"); // When passed to calculateMean // Then it should return their mean // Delete this test.todo and replace it with a test. -test.todo("given [1, 2, 6], returns 3"); +test("given [1, 2, 6], returns 3", () => { + const list = [1, 2, 6]; + const result = calculateMean(list); + expect(result).toEqual(3); +}); // Given an array with a single number // When passed to calculateMean // Then it should return that number +test("given [6], returns 6", () => { + expect(6).toEqual(6); +}); // Given an array containing negative or decimal numbers // When passed to calculateMean // Then it should return the correct mean +test("given negative numbers, return mean", () => { + const list = [-7, -3, -5]; + const result = calculateMean(list); + expect(result).toEqual(-5); +}); + + test("given decimal numbers, return mean", () => { + const list = [7.2, 2.4, 6.8]; + const result = calculateMean(list); + expect(result).toBeCloseTo(5.47); +}); // Given an empty array // When passed to calculateMean // Then it should throw Error("calculateMean requires a non-empty array") +test("given an empty array, returns, calculateMean requires a non-empty array", () => { + expect(() => calculateMean([])).toThrow( + new Error("calculateMean requires a non-empty array") + ); +}); // Given a value that isn't an array, e.g. "banana", 42, null or {} // When passed to calculateMean // Then it should throw Error("calculateMean requires an array of numbers") +test("given a non-array, returns, calculateMean requires an array of numbers", () => { + expect(() => calculateMean("banana", 42, null, {})).toThrow( + new Error("calculateMean requires an array of numbers") + ); +}); // Given no argument at all // When passed to calculateMean // Then it should throw Error("calculateMean requires an array of numbers") +test("given no argument, returns, calculateMean requires an array of numbers", () => { + expect(() => calculateMean()).toThrow( + new Error("calculateMean requires an array of numbers") + ); +}); // Given an array containing a non-number value, e.g. [1, "2", 3] // When passed to calculateMean // Then it should throw Error("calculateMean requires an array of numbers") +test("given non-number containing array, returns, calculateMean requires an array of numbers", () => { + expect(() => calculateMean([1, "2", 3])).toThrow( + new Error("calculateMean requires an array of numbers") + ); +}); diff --git a/Sprint-1/implement/sum.js b/Sprint-1/implement/sum.js index 9062aafe3..f5ccb538b 100644 --- a/Sprint-1/implement/sum.js +++ b/Sprint-1/implement/sum.js @@ -1,4 +1,15 @@ function sum(elements) { + if (!Array.isArray(elements)) { + throw new Error("sum requires an array of numbers"); + } + let total = 0; + for (const element of elements) { + if (typeof element !== "number") { + throw new Error("sum requires an array of numbers"); + } + total += element; + } + return Number(total.toFixed(2)); } module.exports = sum; diff --git a/Sprint-1/implement/sum.test.js b/Sprint-1/implement/sum.test.js index a288e0f0a..172daac6d 100644 --- a/Sprint-1/implement/sum.test.js +++ b/Sprint-1/implement/sum.test.js @@ -13,24 +13,45 @@ 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") +test("given an empty array, returns 0", () => { + expect(sum([])).toEqual(0); +}); // Given an array with just one number // When passed to the sum function // Then it should return that number +test("given a one number array, returns the same number", () => { + expect(sum([9])).toEqual(9); +}); // Given an array containing negative numbers // When passed to the sum function // Then it should still return the correct total sum +test("given a negative number array, returns the sum", () => { + expect(sum([-9, -3, -6])).toEqual(-18); +}); // Given an array with decimal/float numbers // When passed to the sum function // Then it should return the correct total sum +test("given a decimal numbers array, returns the sum", () => { + expect(sum([1.9, 7.5, 4.91])).toBeCloseTo(14.31); +}); // Given an array containing a value that isn't a number // When passed to the sum function // Then it should throw Error("sum requires an array of numbers") +test("given a non-numbers array, returns sum requires an array of numbers", () => { + expect(() => sum(["apple", null ,3])).toThrow( + new Error("sum requires an array of numbers") + ); +}); // Given something that isn't an array at all, such as "hey", 42 or no argument // When passed to the sum function // Then it should throw Error("sum requires an array of numbers") +test("given a non-array, returns sum requires an array of numbers", () => { + expect(() => sum("apple", null, 3)).toThrow( + new Error("sum requires an array of numbers") + ); +}); \ No newline at end of file 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; } diff --git a/Sprint-1/stretch/aoc-2018-day1/solution.js b/Sprint-1/stretch/aoc-2018-day1/solution.js index e69de29bb..c746c509c 100644 --- a/Sprint-1/stretch/aoc-2018-day1/solution.js +++ b/Sprint-1/stretch/aoc-2018-day1/solution.js @@ -0,0 +1,14 @@ +const fs = require("fs"); +const inputText = fs.readFileSync("input.txt", "utf8"); + +function calculateResultingFrequency(frequencyChangeLines) { + const lines = frequencyChangeLines.split("\n"); + const frequencyChangeAsNumbers = lines.map((change) => Number(change)); + let resultingFrequency = 0; + + for (const frequencyChange of frequencyChangeAsNumbers) { + resultingFrequency += frequencyChange; + } + return resultingFrequency; +} +console.log(calculateResultingFrequency(inputText));