diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..f0d22ec4f 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,9 +1,7 @@ // Predict and explain first... - // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working - const address = { houseNumber: 42, street: "Imaginary Road", @@ -12,4 +10,10 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +// console.log(`My house number is ${address[0]}`); +// is trying to access a property using address[0] and address is an object, not an array. +// it will log undefined. +// to access the houseNumber property, we should use dot notation or bracket notation with string,and either +// way using object.key or object["key"] +console.log(`My house number is ${address.houseNumber}`); +console.log(`My house number is ${address["houseNumber"]}`); diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..ebe39c1a4 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -11,6 +11,12 @@ const author = { alive: true, }; -for (const value of author) { +// for (const value of author) { +// console.log(value); +// } +// It will log syntax Error because Objects themselves aren’t directly iterable Unlike arrays we need to converted +// and then we can loop + +for (const value of Object.values(author)) { console.log(value); } diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..c46604ce8 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -3,13 +3,19 @@ // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line // How can you fix it? - const recipe = { title: "bruschetta", serves: 2, ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +// console.log(`${recipe.title} serves ${recipe.serves} +// ingredients: +// ${recipe}`); +// When you using ${recipe} in a template literal javaScript tries to convert the entire object to a string +// it will log [object Object]. +console.log(`${recipe.title} serves ${recipe.serves}`); +console.log("ingredients"); +recipe.ingredients.forEach((ingredient) => { + console.log(ingredient); +}); diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..fcda136fa 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,5 @@ -function contains() {} - +function contains(obj, propertyName) { + return obj && typeof obj === "object" && propertyName in obj; +} +// console.log(contains(({ a: 1, b: 2 }, "c"))); module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..c835f7460 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,31 @@ as the object doesn't contains a key of 'c' // Given a contains function // When passed an object and a property name // Then it should return true if the object contains the property, false otherwise +test("contains returns true for existing property", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBe(true); +}); -// Given an empty object +// Given invalid parameters like an array // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); - +test("contains on empty object returns false", () => { + expect(contains([], "a")).toBe(false); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true - +test("Given an object with an existing property should return true", () => { + expect(contains({ a: 1, k: 2 }, "k")).toBe(true); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false - +test("Given an object with none-existing property should return false", () => { + expect(contains({ a: 1, b: 2 }, "c")).toBe(false); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("Given an object with an existing property should return true", () => { + expect(contains(["k", "a"], "k")).toBe(false); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..af77024a6 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,8 @@ -function createLookup() { - // implementation here +function createLookup(nestedArr) { + const result = {}; + for (const [country, currency] of nestedArr) { + result[country] = currency; + } + return result; } - module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..761632b39 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,35 +1,26 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); - -/* - -Create a lookup object of key value pairs from an array of code pairs - -Acceptance Criteria: - -Given - - An array of arrays representing country code and currency code pairs - e.g. [['US', 'USD'], ['CA', 'CAD']] - -When - - createLookup function is called with the country-currency array as an argument - -Then - - It should return an object where: - - The keys are the country codes - - The values are the corresponding currency codes - -Example -Given: [['US', 'USD'], ['CA', 'CAD']] - -When -createLookup(countryCurrencyPairs) is called - -Then -It should return: - { - 'US': 'USD', - 'CA': 'CAD' - } -*/ +// Create a lookup object of key value pairs from an array of code pairs + +// Acceptance Criteria: + +// Given +// - An array of arrays representing country code and currency code pairs +// e.g. [['US', 'USD'], ['CA', 'CAD']] +test("creates a country currency code lookup for multiple codes", () => { + expect( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) + ).toEqual({ US: "USD", CA: "CAD" }); +}); + +test("creates a lookup for European and Asian countries", () => { + expect( + createLookup([ + ["FR", "EUR"], + ["IN", "INR"], + ]) + ).toEqual({ FR: "EUR", IN: "INR" }); +}); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..f37b97037 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -3,14 +3,22 @@ function parseQueryString(queryString) { if (queryString.length === 0) { return queryParams; } + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + const indexOfEquals = pair.indexOf("="); + + if (indexOfEquals === -1) { + queryParams[pair] = ""; + } else { + const key = pair.slice(0, indexOfEquals); + const value = pair.slice(indexOfEquals + 1); + queryParams[key] = value; + } } return queryParams; } - +console.log(parseQueryString("equation=x=y+1")); module.exports = parseQueryString; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..d2e878ed9 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -3,10 +3,40 @@ // Below is one test case for an edge case the implementation doesn't handle well. // Fix the implementation for this test, and try to think of as many other edge cases as possible - write tests and fix those too. -const parseQueryString = require("./querystring.js") - +const parseQueryString = require("./querystring.js"); test("parses querystring values containing =", () => { expect(parseQueryString("equation=x=y+1")).toEqual({ - "equation": "x=y+1", + equation: "x=y+1", + }); +}); +test("parses simple key=value pairs", () => { + expect(parseQueryString("name=John&age=30")).toEqual({ + name: "John", + age: "30", + }); +}); + +test("parses value containing '='", () => { + expect(parseQueryString("equation=x=y+1")).toEqual({ + equation: "x=y+1", + }); +}); + +test("handles keys with no value", () => { + expect(parseQueryString("flag&key=value")).toEqual({ + flag: "", + key: "value", + }); +}); + +test("handles multiple '=' in value", () => { + expect(parseQueryString("data=key=value=extra")).toEqual({ + data: "key=value=extra", + }); +}); + +test("handles keys with empty values", () => { + expect(parseQueryString("name=")).toEqual({ + name: "", }); }); diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..22d08dda3 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,11 @@ -function tally() {} - +function tally(arr) { + const output = {}; + if (!Array.isArray(arr)) { + throw new Error("Input must be an array"); + } + arr.forEach((element) => { + output[element] = (output[element] || 0) + 1; + }); + return output; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..ec2584c3c 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,25 @@ const tally = require("./tally.js"); // Given a function called tally // When passed an array of items // Then it should return an object containing the count for each unique item - +test("Given a function called tally, should return an object containing the count for each unique item", () => { + expect(tally(["a", "a", "a"])).toEqual({ a: 3 }); +}); // Given an empty array // When passed to tally // Then it should return an empty object -test.todo("tally on an empty array returns an empty object"); - +test("Given an empty array [], should returns an empty object {}", () => { + expect(tally([])).toEqual({}); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("Given an array with duplicate items, should return counts for each unique item", () => { + expect(tally(["a", "a", "b", "c"])).toEqual({ a: 2, b: 1, c: 1 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("Given an invalid input like a string,Then it should throw an error", () => { + expect(() => tally("string")).toThrow("Input must be an array"); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..a7e7a557e 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,25 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } // a) What is the current return value when invert is called with { a : 1 } - +// {"1":"a"} // b) What is the current return value when invert is called with { a: 1, b: 2 } - +// { "1": "a", "2": "b" } // c) What is the target return value when invert is called with {a : 1, b: 2} - +// { a: 1, b: 2 } // c) What does Object.entries return? Why is it needed in this program? +// returns an array of a given object's which is own enumerable string-keyed property key-value pairs. // d) Explain why the current return value is different from the target output - +// The code uses invertedObj.key = value which creates a property literally named "key" instead of dynamically using the value of key // e) Fix the implementation of invert (and write tests to prove it's fixed!) +console.log(invert({ a: 2, b: 3 })); // ===> { '2': 'a', '3': 'b' } +console.log(invert({ b: 1, c: 2 })); // ===> { '1': 'b', '2': 'c' } +console.log(invert({ code: "war" })); // ===> { war: 'code' +console.log(invert({})); // ===> {} diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 8e85d19d7..5e936ba17 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -26,3 +26,17 @@ 3. Order the results to find out which word is the most common in the input */ +function countWords(str) { + const obj = {}; + let tidyStr = str.replace(/[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g, ""); + let arr = tidyStr.toLowerCase().split(/\s+/); + arr.forEach((element) => { + if (obj[element]) { + obj[element] += 1; + } else { + obj[element] = 1; + } + }); + return obj; +} +// countWords("you and mE anD you me! me"); diff --git a/Sprint-2/stretch/mode.js b/Sprint-2/stretch/mode.js index 3f7609d79..b73a52eb4 100644 --- a/Sprint-2/stretch/mode.js +++ b/Sprint-2/stretch/mode.js @@ -19,8 +19,11 @@ function calculateMode(list) { freqs.set(num, (freqs.get(num) || 0) + 1); } + return highestFreq(freqs); +} - // Find the value with the highest frequency +// Find the value with the highest frequency +function highestFreq(freqs) { let maxFreq = 0; let mode; for (let [num, freq] of freqs) { @@ -32,5 +35,4 @@ function calculateMode(list) { return maxFreq === 0 ? NaN : mode; } - module.exports = calculateMode; diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 6a08532e7..4cbe47135 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -8,7 +8,8 @@ function totalTill(till) { let total = 0; for (const [coin, quantity] of Object.entries(till)) { - total += coin * quantity; + const formatedCoin = parseInt(coin); + total += formatedCoin * quantity; } return `£${total / 100}`; @@ -20,12 +21,43 @@ const till = { "50p": 4, "20p": 10, }; + const totalAmount = totalTill(till); // a) What is the target output when totalTill is called with the till object +// Sum = 10 + 30 + 200 + 200 = 440p → £4.40 // b) Why do we need to use Object.entries inside the for...of loop in this function? +// it used to convert the object into an array of key-value pairs. // c) What does coin * quantity evaluate to inside the for...of loop? +// Coin is a string like "1p", "5p", etc. Multiplying a string that includes non-numeric characters by a number resulting into a NaN which is not a number. // d) Write a test for this function to check it works and then fix the implementation of totalTill +const till1 = { + "11p": 5, + "7p": 4, + "40p": 3, + "80p": 1, +}; + +const expected1 = "£2.83"; +const actual1 = totalTill(till1); +console.assert( + actual1 === expected1, + `Expected ${expected1} but got ${actual1}` +); + +const till2 = { + "21p": 9, + "3p": 2, + "9p": 9, + "44p": 7, +}; + +const expected2 = "£5.84"; +const actual2 = totalTill(till2); +console.assert( + actual2 === expected2, + `Expected ${expected2} but got ${actual2}` +);