diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..7368f1e13 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,5 +1,10 @@ // Predict and explain first... +/* +Objects don't use indexes like arrays. If we try to access address[0], it returns undefined because address +is an object, not an array. Objects store values using keys (property names). To retrieve a value, we can use +either dot notation, such as address.houseNumber, or bracket notation, such as address["houseNumber"]. +*/ // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working @@ -12,4 +17,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(`My house number is ${address.houseNumber}`); diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..87eea84cf 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,8 +1,14 @@ // Predict and explain first... - +/* +author is an object. The original code tries to use a for...of loop directly on the object, but normal objects +cannot be directly iterated using for...of. Since we only want the property values, we can use Object.values(author) +to get all the values from the object. + */ // 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", @@ -10,7 +16,5 @@ const author = { age: 40, alive: true, }; +console.log(Object.values(author)); -for (const value of author) { - console.log(value); -} diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..081d1993e 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,5 +1,9 @@ // Predict and explain first... - +/* +The printing of title and serves is absolutely correct, but to print ingredients on a new line isn't correct. +To retrieve values, we use Object.values(recipe). To print ${recipe} isn't the right way. We can use a for...of +loop to print each ingredient on a new line. +*/ // 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? @@ -10,6 +14,7 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(`${recipe.title} serves ${recipe.serves}`); +for(let values of Object.values(recipe.ingredients)){ + console.log(values); +} diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..0ed225476 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,14 @@ -function contains() {} +function contains(obj, item) { + if (typeof obj !== "object" || obj === null || Array.isArray(obj)){ + return false; + } + let getKey = Object.keys(obj); + for (let element of getKey){ + if(element === item){ + return true + } + } + return false; +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..1edce369b 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -11,25 +11,37 @@ E.g. contains({a: 1, b: 2}, 'c') // returns false as the object doesn't contains a key of 'c' */ -// Acceptance criteria: - // 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("return true if object's property exists otherwise false", () => { + expect(contains({name: "maryam", city: "Derby"}, "city")).toBe(true); +}); // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); +test("return false if object is empty", () => { + 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("return true if object's property contains the property", () => { + expect(contains({name: "maryam", city: "Derby"}, "city")).toBe(true); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("return false if property is non-existent", () => { + expect(contains({name: "maryam", city: "Derby"}, "age")).toBe(false); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("return false if it's not an object", () => { + expect(contains([], 6)).toBe(false); +}); \ No newline at end of file diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..d826d656e 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,7 @@ -function createLookup() { +function createLookup(arr) { // implementation here + const obj = Object.fromEntries(arr); + return obj; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..66d85f7a5 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,19 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); +test("creates a country currency code lookup for multiple codes", () =>{ + expect(createLookup([['US', 'USD'], ['CA', 'CAD'], ['PAK', 'PKR'], ['SAUDI', 'RIYAL']])).toEqual({ + 'US': 'USD', + 'CA': 'CAD', + 'PAK' : 'PKR', + 'SAUDI' : 'RIYAL' + }); +}); +test("the array is empty", () =>{ + expect(createLookup([])).toEqual({}); +}); +test("creates a country currency code lookup for single code", () =>{ + expect(createLookup([['Uk','POUND']])).toEqual({'Uk': 'POUND'}); +}); /* diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..cca92c87c 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,16 +1,48 @@ function parseQueryString(queryString) { const queryParams = {}; + if (queryString.length === 0) { return queryParams; } + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + if (pair === "") { + continue; + } + + const checkSeparator = pair.indexOf("="); + + let key; + let value; + + if (checkSeparator === -1) { + key = pair; + value = ""; + } else { + key = pair.slice(0, checkSeparator); + value = pair.slice(checkSeparator + 1); + } + + key = key.replace(/\+/g, " "); + value = value.replace(/\+/g, " "); + + key = decodeURIComponent(key); + value = decodeURIComponent(value); + + if (Object.prototype.hasOwnProperty.call(queryParams, key)) { + if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } + } else { + queryParams[key] = value; + } } return queryParams; } -module.exports = parseQueryString; +module.exports = parseQueryString; \ No newline at end of file diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 328b8df61..cb2d42012 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -46,3 +46,33 @@ test("should store values of a key in an array when the key has 2 or more values foo: "bar", }); }); +// Multiple normal key-value pairs +test("should parse multiple key-value pairs", () => { + expect(parseQueryString("name=Maryam&age=25")).toEqual({ + name: "Maryam", + age: "25", + }); +}); + +test("should return empty object for empty query string", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("should replace multiple '+' characters with spaces", () => { + expect(parseQueryString("name=John+Michael+Doe")).toEqual({ + name: "John Michael Doe", + }); +}); + +test("should decode encoded keys and values", () => { + expect(parseQueryString("hello%20world=good%20morning")).toEqual({ + "hello world": "good morning", + }); +}); + +test("should ignore multiple empty key-value pairs", () => { + expect(parseQueryString("name=Maryam&&&age=25&&&")).toEqual({ + name: "Maryam", + age: "25", + }); +}); \ No newline at end of file diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..e4db6c1ef 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,14 @@ -function tally() {} - +function tally(arr) { + const result = arr.reduce((obj, item) => { + if (obj [item]) { + obj[item] = obj[item] + 1; + } + else{ + obj[item] = 1; + } + return obj; + }, {}); + + return result; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..1a88bb231 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,52 @@ 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("when an array is passed, it should return an object containing the count for each unique item", () => { + expect(tally(["banana", "apple", "cherry", "apple", "cherry"])).toEqual({ + banana: 1, + apple: 2, + cherry: 2 + }); +}); // 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("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("should return the count for duplicate items", () => { + expect(tally(["apple", "apple", "apple", "banana"])).toEqual({ + apple: 3, + banana: 1 + }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("should throw an error when passed a string", () => { + expect(() => tally("apple")).toThrow(); +}); + +// Case: array containing numbers +test("should count occurrences of numbers", () => { + expect(tally([1, 2, 2, 3, 3, 3])).toEqual({ + 1: 1, + 2: 2, + 3: 3 + }); +}); + +// Case: array containing mixed data types +test("should count occurrences of mixed items", () => { + expect(tally(["apple", 1, "apple", 1, "banana"])).toEqual({ + apple: 2, + 1: 2, + banana: 1 + }); +}); \ No newline at end of file diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..249c86257 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,40 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj.key = value; // key 1 } return invertedObj; } // a) What is the current return value when invert is called with { a : 1 } +// {key : 1} // b) What is the current return value when invert is called with { a: 1, b: 2 } +// {key ; 2} // c) What is the target return value when invert is called with {a : 1, b: 2} +// {1 : "a", 2 : "b"} // c) What does Object.entries return? Why is it needed in this program? +// It returns all the key-value pairs of an object. We need it to get both the keys and values. // d) Explain why the current return value is different from the target output +/*Because we are not swapping it correctly. We haven't handled the key correctly, + so it's giving us the "key" keyword, not the way we need it. + Plus, we aren't storing each value correctly, so the previous value gets overwritten + when there are multiple values.*/ -// e) Fix the implementation of invert (and write tests to prove it's fixed!) +//e) Fix the implementation of invert (and write tests to prove it's fixed!) + +function invert(obj) { + const invertedObj = {}; + + for (const [key, value] of Object.entries(obj)) { + invertedObj[value] = key; + } + + return invertedObj; +} +const obj = {x : 10, y : 20}; +console.log(invert(obj)); \ No newline at end of file