diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..5467ea0e8 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -12,4 +12,6 @@ const address = { postcode: "XYZ 123", }; +// console.log(`${address[2]}`) console.log(`My house number is ${address[0]}`); + diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..ecfa3c0e1 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,8 +1,12 @@ // Predict and explain first... +// TypeError: author is not iterable because A for...of loop is used for iterable things such as arrays, strings, Maps, and Sets. + +// But author is a plain object. Plain objects aren't directly iterable with for...of. + +// To loop through an object's values, use: // This program attempts to log out all the property values in the object. // But it isn't working. Explain why first and then fix the problem - const author = { firstName: "Zadie", lastName: "Smith", @@ -11,6 +15,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value of Object.values(author)) { console.log(value); -} +} \ No newline at end of file diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..0d9b65961 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,5 +1,7 @@ // Predict and explain first... - +// the code might print something like this bruschetta serves 2 +//ingredients: [object Object] because the ${recipe} is an object and we only trying to print the +// ingredients inside the object // 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? @@ -11,5 +13,5 @@ const recipe = { }; console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +ingredients: +${recipe.ingredients.join("\n")}`); diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..078449f3c 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,11 @@ -function contains() {} +function contains(object, property) { + if (typeof object !== "object" || object === null || Array.isArray(object)) { + return false; + } + + return Object.hasOwn(object, property); +} module.exports = contains; + + diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..52d343f5c 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -21,15 +21,26 @@ as the object doesn't contains a key of 'c' // 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("contains returns true when property exists", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBe(true); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("contains returns false when property does not exist", () => { + 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("contains returns false when passed an array", () => { + expect(contains([], "a")).toBe(false); +}); \ No newline at end of file diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..71b45e605 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,15 @@ -function createLookup() { +function createLookup(countryCurrencyPairs) { // implementation here + const lookup = {}; + + for (const pair of countryCurrencyPairs) { + const [countryCode, currencyCode] = pair; + lookup[countryCode] = currencyCode; + } + + return lookup; } module.exports = createLookup; + +module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..245a1e158 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -33,3 +33,14 @@ It should return: 'CA': 'CAD' } */ +test("creates a country currency code lookup for multiple codes", () => { + const countryCurrencyPairs = [ + ["US", "USD"], + ["CA", "CAD"], + ]; + + expect(createLookup(countryCurrencyPairs)).toEqual({ + US: "USD", + CA: "CAD", + }); +}); \ No newline at end of file diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..f75f93a10 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,13 +1,50 @@ function parseQueryString(queryString) { const queryParams = {}; + + // If the query string is empty, return an empty object if (queryString.length === 0) { return queryParams; } + + // Split the query string into separate key-value pairs const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + // Ignore empty pairs + if (pair === "") { + continue; + } + + // Find the first "=" + const equalsPosition = pair.indexOf("="); + + let key; + let value; + + // If there is no "=" + if (equalsPosition === -1) { + key = pair; + value = ""; + } else { + // Everything before "=" is the key + key = pair.substring(0, equalsPosition); + + // Everything after the first "=" is the value + value = pair.substring(equalsPosition + 1); + } + + // Replace "+" with spaces and decode special characters + key = decodeURIComponent(key.replace(/\+/g, " ")); + value = decodeURIComponent(value.replace(/\+/g, " ")); + + // If the key already exists, store multiple values in an array + if (queryParams[key] === undefined) { + queryParams[key] = value; + } else if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } } return queryParams; diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..28b2d5288 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,21 @@ -function tally() {} +function tally(items) { + // Check that the input is an array + if (!Array.isArray(items)) { + throw new Error("Input must be an array"); + } + + const counts = {}; + + // Go through each item in the array + for (const item of items) { + if (counts[item] === undefined) { + counts[item] = 1; + } else { + counts[item] = counts[item] + 1; + } + } + + return counts; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..bea83034a 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -24,11 +24,23 @@ const tally = require("./tally.js"); // When passed to tally // Then it should return an empty object test.todo("tally on an empty array returns an empty object"); - +test("tally on an empty array 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("tally counts duplicate items", () => { + 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("tally throws an error when given a string", () => { + expect(() => tally("hello")).toThrow(); +}); \ No newline at end of file diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..55329026b 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,28 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } +module.exports = invert // a) What is the current return value when invert is called with { a : 1 } +// {key: 1} because the invertedObj,ket = value does not use the variable key + // b) What is the current return value when invert is called with { a: 1, b: 2 } +// {key:2} the loop runs twice and the second iteration replaces the first one so the answer becomes 2 // c) What is the target return value when invert is called with {a : 1, b: 2} +// The target return value is to swap the keys and values so {a:1, b:2} becomes {1:a, 2:b} // c) What does Object.entries return? Why is it needed in this program? +// Object.entries() turns an object into an array containing key-value pairs // d) Explain why the current return value is different from the target output - +// invertedObj.key means to create or access an object called key +// and inverted invertedObj[key] means to use whatever value is stored in the key variable // e) Fix the implementation of invert (and write tests to prove it's fixed!) + diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js new file mode 100644 index 000000000..2db3aa954 --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,21 @@ +const invert = require("./invert.js"); + +test("inverts an object with one property", () => { + expect(invert({ a: 1 })).toEqual({ + 1: "a", + }); +}); + +test("inverts an object with multiple properties", () => { + expect(invert({ a: 1, b: 2 })).toEqual({ + 1: "a", + 2: "b", + }); +}); + +test("inverts the example object", () => { + expect(invert({ x: 10, y: 20 })).toEqual({ + 10: "x", + 20: "y", + }); +});