diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index b22590bc6..af0bcf4b0 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -5,10 +5,56 @@ // Hint: Please consider scenarios when 'list' doesn't have numbers (the function is expected to return null) // or 'list' has mixed values (the function is expected to sort only numbers). +//function should not change the original array +//function should sort a copy of the array +//function should check if array has any non number values +//function should check if array has even number of integers or odd number before attempting to calculate median +// + function calculateMedian(list) { - const middleIndex = Math.floor(list.length / 2); - const median = list.splice(middleIndex, 1)[0]; - return median; + //first we create an array and copy only numbers into it + //because we use array methods first we check we are passing an array + let numberArray = []; + + function isNumber(value) { + if (typeof value === "number") { + return true; + } + + return false; + } + + function compareNumbers(a, b) { + return a - b; + } + + if (Array.isArray(list)) { + //checking if we have been passed an array before picking numbers from any arrays + numberArray = list.filter(isNumber); + console.log(`new array ${numberArray}`); + } else { + return null; + } + + numberArray.sort(compareNumbers); //sorting the copied array of numbers + + //quickly check if the new array is empty which means there were no numbers in original array + if (numberArray.length === 0) { + return null; + } + + let middleIndex = 0; + let middleIndexPlus1 = 0; + + if (numberArray.length % 2 === 0) { + //if array has even number of items then a different median formula + middleIndex = Math.floor(numberArray.length / 2); + middleIndexPlus1 = middleIndex - 1; + + return (numberArray[middleIndex] + numberArray[middleIndexPlus1]) / 2; + } + + return numberArray.splice(Math.floor(numberArray.length / 2), 1)[0]; } module.exports = calculateMedian; diff --git a/Sprint-1/implement/dedupe.js b/Sprint-1/implement/dedupe.js index 781e8718a..069b8e1f8 100644 --- a/Sprint-1/implement/dedupe.js +++ b/Sprint-1/implement/dedupe.js @@ -1 +1,50 @@ -function dedupe() {} +function dedupe(myArray) { + //check array for duplicates + //for each item compare to all other items and return true if duplicate found + //if none return copy of array + function checkForDupe(item) { + let counter = 0; + for (let value of myArray) { + if (item === value) { + counter++; + } + } + if (counter > 1) { + return false; + } else { + return true; + } + } + + if (myArray.length === 0) { + //return empty array for empty array + return []; + } else if (myArray.length === myArray.filter(checkForDupe).length) { + //return copy of array if no duplicates + return myArray; + } + + //to remove duplicates first we take a given item in an array + //and compare it to all the other items in the array. + //we will need a counter to keep track of the number of times an item matches + //we only want to keep items with a count of 1 + //so for any matches with a count of 2 or more we remove the item at the matching index + + myArray.forEach((item) => { + let matchCount = 0; + + for (let i = 0; i < myArray.length; i++) { + if (item === myArray[i]) { + matchCount++; + + if (matchCount > 1) { + myArray.splice(i, 1); + } + } + } + }); + + return myArray; +} + +module.exports = dedupe; diff --git a/Sprint-1/implement/dedupe.test.js b/Sprint-1/implement/dedupe.test.js index 23e0f8638..a5751f1ce 100644 --- a/Sprint-1/implement/dedupe.test.js +++ b/Sprint-1/implement/dedupe.test.js @@ -16,12 +16,53 @@ 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"); +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 +describe("returning copies of arrays with no duplicates", () => { + [ + { input: [1, 4, 5, 6, 2, 7, 8, 45], expected: [1, 4, 5, 6, 2, 7, 8, 45] }, + { + input: [1, 3, 5, 7, 9, 15, 17, 19], + expected: [1, 3, 5, 7, 9, 15, 17, 19], + }, + { + input: [1, 3, 50, 732, 987, 15000, 1790, 190], + expected: [1, 3, 50, 732, 987, 15000, 1790, 190], + }, + { + input: ["one", "jim", 5, "messy", "tip", 15, "random", 19], + expected: ["one", "jim", 5, "messy", "tip", 15, "random", 19], + }, + ].forEach(({ input, expected }) => + it("returns a copy of the original array for arrays with no duplicates", () => + expect(dedupe(input)).toEqual(expected)) + ); +}); // 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("removing duplicate values but keeping the first occurance of each element", () => { + [ + { + input: [1, 2, 2, "cat", "dog", 9, "man", "cat"], + expected: [1, 2, "cat", "dog", 9, "man"], + }, + { + input: ["ben", "two", "two", 2, "shine", "count", 9, "man"], + expected: ["ben", "two", 2, "shine", "count", 9, "man"], + }, + { + input: ["ben", "two", "ben", 2, "ben", "ben", 2, "man", 2], + expected: ["ben", "two", 2, "man"], + }, + ].forEach(({ input, expected }) => + it("removes any duplicate values from the array, keeping the first instance of each element", () => + expect(dedupe(input)).toEqual(expected)) + ); +}); diff --git a/Sprint-1/implement/max.js b/Sprint-1/implement/max.js index 6dd76378e..48311e723 100644 --- a/Sprint-1/implement/max.js +++ b/Sprint-1/implement/max.js @@ -1,4 +1,47 @@ function findMax(elements) { + if (elements.length === 0) { + return -Infinity; + } else if (elements.length === 1) { + return elements[0]; + } + + let largestNum = 0; + let largestValue = ""; + let countNum = 0; + + if (typeof elements[0] === "number") { + largestNum = elements[0]; + } else { + let largestValue = elements[0]; + } + + for (let i = 1; i < elements.length; i++) { + if (typeof elements[i] === "number") { + countNum++; + + if (elements[i] > largestNum) { + largestNum = elements[i]; + } + } else { + if (elements[i] > largestValue) { + largestValue = elements[i]; + } + } + + //we create an array of numbers using filter + //if (typeof largestNum !== 'undefined') { + + // numberArray = elements.filter((element) => typeof element === 'number'); + // console.log(numberArray); + + //} + } + + if (countNum > 0) { + return largestNum; + } else { + return largestValue; + } } module.exports = findMax; diff --git a/Sprint-1/implement/max.test.js b/Sprint-1/implement/max.test.js index 82f18fd88..97e785372 100644 --- a/Sprint-1/implement/max.test.js +++ b/Sprint-1/implement/max.test.js @@ -16,28 +16,108 @@ 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, it should return the number", () => + expect(findMax([4])).toEqual(4)); // Given an array with both positive and negative numbers // When passed to the max function // Then it should return the largest number overall +describe("getting the largest number from an array of positive and negative numbers", () => { + [ + { input: [1, -4, -80, 100, -120, 0, 55], expected: 100 }, + { input: [20, 0, -80, 1, -10, -8, 5], expected: 20 }, + { input: [0, -4, -80, -100, -120, 0, -55], expected: 0 }, + { input: [17, -9, -400, 81, 120, 2, 5.5], expected: 120 }, + { input: [-1, -4, -70, 1000, -190, 1456, 0.5], expected: 1456 }, + ].forEach(({ input, expected }) => + it(`returns the largest number overall`, () => + expect(findMax(input)).toBe(expected)) + ); +}); // Given an array with just negative numbers // When passed to the max function // Then it should return the closest one to zero +describe("getting the largest number from an array of negative non-zero numbers", () => { + [ + { input: [-15, -4, -80, -100, -120, -7, -55], expected: -4 }, + { input: [-20, -90, -800, -11, -19, -8, -23], expected: -8 }, + { + input: [-890, -6734, -89230, -1780, -128, -863927, -9076], + expected: -128, + }, + { + input: [-1789, -1098, -1400, -1891, -1620, -2623, -3558], + expected: -1098, + }, + { + input: [-1893, -490365, -709, -1000, -1790, -91456, -708], + expected: -708, + }, + ].forEach(({ input, expected }) => + it(`returns the closest negative number to zero`, () => + 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 +describe("getting the largest decimal number from an array of positive and negative numbers", () => { + [ + { input: [1.5, -4.8, -80.87, 1.09, -1.2, 0.967, 5.95], expected: 5.95 }, + { input: [2.0, 9.7, -20.801, 21.7, -10.9, 3.768, 56.4], expected: 56.4 }, + { input: [0.345, 8.876, 9.56, 34.2, 32.4, 32.212, 31.989], expected: 34.2 }, + { input: [5.5, 7.685, 7.865, 7.6854, 7.6853, 7.6855], expected: 7.865 }, + { input: [-5.674, 9.1, 9.121, 9.122, 9.1221, 9.12213], expected: 9.12213 }, + ].forEach(({ input, expected }) => + it(`returns the largest number overall`, () => + 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 +describe("returning the max number from array with numeric and non-numeric values", () => { + [ + { + input: [1.5, -4.8, "ten", 1.09, "fifty six", 0.967, "six"], + expected: 1.5, + }, + { input: ["twenty", "ben", "x-ray", 23, -10, "joe", 5], expected: 23 }, + { input: ["zero", -4, -80, -100, -120, 0, "tom"], expected: 0 }, + ].forEach(({ input, expected }) => + it(`returns the largest number ignoring 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 +describe("returning the max number from array with numeric and non-numeric values", () => { + [ + { + input: ["dam", "meat", "ten", "faster", "fifty six", "loud", "mix"], + expected: "ten", + }, + { + input: ["twenty", "ben", "x-ray", "king", "clive", "joe", "oxen"], + expected: "x-ray", + }, + { + input: ["zero", "switch", "price", "tom", "max", "nick", "reach"], + expected: "tom", + }, + ].forEach(({ input, expected }) => + it(`returns the largest number ignoring non-numeric values`, () => + expect(findMax(input)).toEqual(expected)) + ); +}); diff --git a/Sprint-1/implement/sum.js b/Sprint-1/implement/sum.js index 9062aafe3..016d2c5b1 100644 --- a/Sprint-1/implement/sum.js +++ b/Sprint-1/implement/sum.js @@ -1,4 +1,53 @@ function sum(elements) { + //function to check the number of decimal places + function numberOfFloat(number) { + if (Number.isInteger(number)) { + return 0; + } else { + return number.toString().split(".")[1].length; + } + } + + function largestFloat(array) { + let largestNum = 0; + let floatValue = 0; + for (number of array) { + floatValue = numberOfFloat(number); + + if (floatValue > largestNum) { + largestNum = floatValue; + } + } + + return largestNum; + } + + const initialValue = 0; + + const numberArray = elements.filter((element) => typeof element === "number"); + + const checkIfFloat = largestFloat(numberArray); + + if (elements.length === 0) { + return 0; + } + + if (numberArray.length > 0) { + const totalSum = numberArray.reduce( + (accumulator, currentValue) => accumulator + currentValue, + initialValue + ); + + if (checkIfFloat === 0) { + return totalSum; + } else { + return Number(totalSum.toFixed(checkIfFloat)); + } + } else { + return elements.reduce( + (accumulator, currentValue) => accumulator + currentValue + ); + } } module.exports = sum; diff --git a/Sprint-1/implement/sum.test.js b/Sprint-1/implement/sum.test.js index dd0a090ca..b30bcf2c6 100644 --- a/Sprint-1/implement/sum.test.js +++ b/Sprint-1/implement/sum.test.js @@ -13,24 +13,87 @@ 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([])).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 the number", () => + expect(sum([8])).toBe(8)); // Given an array containing negative numbers // When passed to the sum function // Then it should still return the correct total sum +describe("returning total sum of negative numbers", () => { + [ + { input: [-1, -5, -45, -32, -23, -17, -26], expected: -149 }, + { input: [-34, -1, -10, -7, -15, -11, -80], expected: -158 }, + { input: [-1000, -500, -450, -320, -2300, -170, -260], expected: -5000 }, + ].forEach(({ input, expected }) => + it(`should return correct total sum from array of negative numbers`, () => + expect(sum(input)).toBe(expected)) + ); +}); // Given an array with decimal/float numbers // When passed to the sum function // Then it should return the correct total sum +describe("returning sum of float numbers", () => { + [ + { + input: [-1.6, -5.765, -4.512, 32.7, 23.9, 1.97, 2.36], + expected: 49.053, + }, + { + input: [-34.6, 1.87, 10.67, -7.984, 15.5, -1.1, 8.0], + expected: -7.644, + }, + { + input: [-10.01, 5.005, 4.5, 3.2, -230.09, 170.76, 260.4], + expected: 203.765, + }, + ].forEach(({ input, expected }) => + it(`should return correct total sum from array of decimal/float numbers`, () => + expect(sum(input)).toBe(expected)) + ); +}); // 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 +describe("returning total sum of numbers from an array with a mix of numbers and non-number values", () => { + [ + { input: [-1, 5, "grumpy", -32, 23, "seventeen", 6], expected: 1 }, + { + input: ["richard", "calculus", 10, -7, 15, 11, "tremulous"], + expected: 29, + }, + { + input: [1000, -500, 450, "number", "joe", -170, "glitch"], + expected: 780, + }, + ].forEach(({ input, expected }) => + it(`should return correct total sum of number values only`, () => + expect(sum(input)).toBe(expected)) + ); +}); // 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 +describe("returning least surprising value based on behavior for non-number values ", () => { + [ + { + input: ["Hi ", "jim ", "what ", "are you ", "doing", "?"], + expected: "Hi jim what are you doing?", + }, + { + input: ["the ", "quick ", "brown ", "fox ", "jumped"], + expected: "the quick brown fox jumped", + }, + { input: [-1000, -500, -450, -320, -2300, -170, -260], expected: -5000 }, + ].forEach(({ input, expected }) => + it(`should return the least surprising value based on the inputs`, () => + expect(sum(input)).toBe(expected)) + ); +}); 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..3fb6735cb 100644 --- a/Sprint-1/refactor/includes.js +++ b/Sprint-1/refactor/includes.js @@ -1,12 +1,13 @@ // 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 (item of list) { + const element = item; if (element === target) { return true; } } + return false; } diff --git a/prep/mean.js b/prep/mean.js new file mode 100644 index 000000000..31f463f9c --- /dev/null +++ b/prep/mean.js @@ -0,0 +1,18 @@ +//a data structure is used to group data together. it is a collection of data which has functions which allow you to access and manipulate the data. +//an array is a zero indexed collection of data that holds data in an ordered list. +function calculateMean(list) { + let total = 0; + + for (const item of list) { + total += item; + } +} + +function calculateMedian(list) { + const middleIndex = Math.floor(list.length / 2); + const median = list.splice(middleIndex, 1)[0]; + + return median; +} + +calculateMean([10, 20, 30, 40, 50]); diff --git a/prep/mean.test.js b/prep/mean.test.js new file mode 100644 index 000000000..386732522 --- /dev/null +++ b/prep/mean.test.js @@ -0,0 +1,22 @@ +test("calculates the mean of a list of numbers", () => { + const list = [3, 50, 7]; + const currentOutput = calculateMean(list); + const targetOutput = 20; + + expect(currentOutput).toEqual(targetOutput); +}); + +test("calculates the median of a list of odd length", () => { + const list = [10, 20, 30, 50, 60]; + const currentOutput = calculateMedian(list); + const targetOutput = 30; + + expect(currentOutput).toEqual(targetOutput); +}); + +test("doesn't modify the input", () => { + const list = [1, 2, 3]; + calculateMedian(list); + + expect(list).toEqual([1, 2, 3]); // Note that the toEqual matcher checks the values inside arrays when comparing them - it doesn't use `===` on the arrays, we know that would always evaluate to false. +}); diff --git a/prep/package.json b/prep/package.json new file mode 100644 index 000000000..2301e1638 --- /dev/null +++ b/prep/package.json @@ -0,0 +1,16 @@ +{ + "name": "prep", + "version": "1.0.0", + "description": "", + "main": "mean.js", + "scripts": { + "test": "jest" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "jest": "^30.2.0" + } +}