From 020a638595ef4931883d64819bc35689bba29b22 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 16:15:30 +0000 Subject: [PATCH 01/14] used a dot notation --- Sprint-2/debug/address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..36d2f865d 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -12,4 +12,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(`My house number is ${address.houseNumber}`); From 00d78e48cede8e8ec6e9230617a5b587a6fa7df2 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 16:29:27 +0000 Subject: [PATCH 02/14] predicted and explained --- Sprint-2/debug/address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 36d2f865d..073565223 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// After i run it will be undefined or throw an error because this is an object not an array to use the square bracket. // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working From 106c8d55eff2e539fc276e33d92c6d0ddc0a70e3 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 16:32:19 +0000 Subject: [PATCH 03/14] changed it to for in loop --- Sprint-2/debug/author.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..4aae5ece2 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// I would say we should use for in loop to log out every value of each key. // 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 @@ -11,6 +11,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value in author) { console.log(value); } From 72464812a4a2dbb09e870cf98121f66772af4095 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 16:44:13 +0000 Subject: [PATCH 04/14] modified author.js --- Sprint-2/debug/author.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 4aae5ece2..8716c3acf 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,5 @@ // Predict and explain first... -// I would say we should use for in loop to log out every value of each key. +// Plain objects are not iterable so we have to use some of the built in object methods. // 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 @@ -11,6 +11,6 @@ const author = { alive: true, }; -for (const value in author) { +for (const value of Object.values (author)) { console.log(value); } From f31c786d5a5819441c4dabb3bff04c486831129a Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 16:58:12 +0000 Subject: [PATCH 05/14] predicted nad fixed recipe.js --- Sprint-2/debug/recipe.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..5cab01a54 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// I think I have to use index to log out every ingredient as it is an array. // 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 +11,9 @@ const recipe = { }; console.log(`${recipe.title} serves ${recipe.serves} - ingredients: + ingredients + ${recipe.ingredients[0]}: + ${recipe.ingredients[1]}: + ${recipe.ingredients[2]}: + ${recipe.ingredients[3]}: ${recipe}`); From 85c361c604f40c0f29c2cb5ea31c7e12171720d6 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 18:20:54 +0000 Subject: [PATCH 06/14] tested my tests --- Sprint-2/implement/contains.js | 11 ++- Sprint-2/implement/contains.test.js | 35 ++++++-- Sprint-2/package.json | 1 + package.json | 127 ++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 package.json diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..2160a0bf8 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,12 @@ -function contains() {} +function contains(obj, key) { + + if(typeof obj !== object || obj === null || Array.isArray(obj)){ + return false; + } + + return obj.hasOwnProperty(key); + + +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..063f46a06 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -8,7 +8,7 @@ E.g. contains({a: 1, b: 2}, 'a') // returns true as the object contains a key of 'a' E.g. contains({a: 1, b: 2}, 'c') // returns false -as the object doesn't contains a key of 'c' +as the object doesn't contain a key of 'c' */ // Acceptance criteria: @@ -20,16 +20,41 @@ as the object doesn't contains a key of 'c' // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); + +test.todo("contains an empty object returns false", () => { + expect(contains({}, "a")).toBe(false); +}); + +// Given invalid parameters like an array +// When passed to contains +// Then it should return false or throw an error + +test("contains array-like object,invalid object and null returns false",() => { + expect(contains([], "a")).toBe(false); + expect(contains(123, "a")).toBe(false); + expect(contains(null, "a")).toBe(false); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test("returns true for existent property", () => { + const obj = {a: 1, b: 2} + expect(contains("a")).toBe(true); +}); + + // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("returns false for non existent properties", () => { + const obj1= {a: 1, b:2} + expect(contains("c")).toBe(false); +}); + + + + + -// Given invalid parameters like an array -// When passed to contains -// Then it should return false or throw an error diff --git a/Sprint-2/package.json b/Sprint-2/package.json index 80c16780f..6fb939824 100644 --- a/Sprint-2/package.json +++ b/Sprint-2/package.json @@ -6,6 +6,7 @@ "scripts": { "test": "jest" }, + "keywords": [], "author": "", "license": "ISC", diff --git a/package.json b/package.json new file mode 100644 index 000000000..26a487990 --- /dev/null +++ b/package.json @@ -0,0 +1,127 @@ +{ + "devDependencies": { + "jest": "^30.2.0", + "test": "^3.3.0" + }, + "name": "module-data-groups", + "version": "1.0.0", + "description": "Like learning a musical instrument, programming requires daily practice.", + "main": "index.js", + "dependencies": { + "abort-controller": "^3.0.0", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "async-function": "^1.0.0", + "available-typed-arrays": "^1.0.7", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "call-bind": "^1.0.8", + "call-bind-apply-helpers": "^1.0.2", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "dunder-proto": "^1.0.1", + "es-abstract": "^1.24.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "event-target-shim": "^5.0.1", + "events": "^3.3.0", + "for-each": "^0.3.5", + "function-bind": "^1.1.2", + "function.prototype.name": "^1.1.8", + "functions-have-names": "^1.2.3", + "generator-function": "^2.0.1", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-bigints": "^1.1.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2", + "ieee754": "^1.2.1", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-async-function": "^2.1.1", + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.2", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.1", + "is-generator-function": "^1.1.2", + "is-map": "^2.0.3", + "is-negative-zero": "^2.0.3", + "is-number-object": "^1.1.1", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakmap": "^2.0.2", + "is-weakref": "^1.1.1", + "is-weakset": "^2.0.4", + "isarray": "^2.0.5", + "math-intrinsics": "^1.1.0", + "minimist": "^1.2.8", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "possible-typed-array-names": "^1.1.0", + "process": "^0.11.10", + "readable-stream": "^4.7.0", + "reflect.getprototypeof": "^1.0.10", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-buffer": "^5.2.1", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-function-length": "^1.2.2", + "set-function-name": "^2.0.2", + "set-proto": "^1.0.0", + "side-channel": "^1.1.0", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2", + "stop-iteration-iterator": "^1.1.0", + "string_decoder": "^1.3.0", + "string.prototype.replaceall": "^1.0.11", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-boxed-primitive": "^1.1.1", + "which-builtin-type": "^1.2.1", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.19" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Fithi-Teklom/Module-Data-Groups.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Fithi-Teklom/Module-Data-Groups/issues" + }, + "homepage": "https://github.com/Fithi-Teklom/Module-Data-Groups#readme" +} From d8bb643e850bab48e09701f9612998d17608ec63 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 18:38:33 +0000 Subject: [PATCH 07/14] made some adjustments for the contains.test.js --- Sprint-2/implement/contains.js | 2 +- Sprint-2/implement/contains.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index 2160a0bf8..e1161c79c 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,6 +1,6 @@ function contains(obj, key) { - if(typeof obj !== object || obj === null || Array.isArray(obj)){ + if(typeof obj !== "object" || obj === null || Array.isArray(obj)){ return false; } diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 063f46a06..afb41a825 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -21,7 +21,7 @@ as the object doesn't contain a key of 'c' // When passed to contains // Then it should return false -test.todo("contains an empty object returns false", () => { +test("contains an empty object returns false", () => { expect(contains({}, "a")).toBe(false); }); @@ -40,7 +40,7 @@ test("contains array-like object,invalid object and null returns false",() => { // Then it should return true test("returns true for existent property", () => { const obj = {a: 1, b: 2} - expect(contains("a")).toBe(true); + expect(contains(obj, "a")).toBe(true); }); From 9547061575d796c1fcfb81b4c30ad24aa9162294 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 30 Nov 2025 19:37:10 +0000 Subject: [PATCH 08/14] done lookup.test.js --- Sprint-2/implement/lookup.js | 7 ++++++- Sprint-2/implement/lookup.test.js | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..2173ee23e 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,10 @@ -function createLookup() { +function createLookup(pairs) { // implementation here + const lookup = {}; + for(const [countryCode, currencyCode]of pairs){ + lookup[countryCode] = currencyCode; + } + return lookup; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..e4218acf0 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,15 @@ 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", () => { + const countryCurrencyPairs = [['US', 'USD'], ['CA', 'CAD']]; + + const expected = { + US: 'USD', + CA: 'CAD', + } + expect(createLookup(countryCurrencyPairs)).toEqual(expected); +}); + /* From 89482b0369f299222b812b1235d37d9d63eb7cff Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 18:17:30 +0000 Subject: [PATCH 09/14] tally.test.js is done --- Sprint-2/implement/querystring.js | 11 ++++++++++- Sprint-2/implement/querystring.test.js | 22 +++++++++++++++++++++- Sprint-2/implement/tally.js | 19 ++++++++++++++++++- Sprint-2/implement/tally.test.js | 24 +++++++++++++++++++++++- Sprint-2/package.json | 2 ++ 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..4ea0244e9 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,11 +6,20 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + + const idx = pair.indexOf("="); + + if (idx === -1) { + // No '=' found, treat entire pair as key with empty value + queryParams[pair] = ""; + } else { + const key = pair.substring(0, idx); + const value = pair.substring(idx + 1); queryParams[key] = value; } return queryParams; } +} module.exports = parseQueryString; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..8adc247e6 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -3,10 +3,30 @@ // 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", }); }); +test("parses empty values", () =>{ + expect(parseQueryString("a=&b=2")).toEqual({a:"",b:"2"}) +}); + +test("parses containing =",() => { + expect(parseQueryString("equation=x=y+1")).toEqual({equation: "x=y+1"}) +}); + + +test("parses empty string", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("parses multiple pairs including empty value", () => { + expect(parseQueryString("a=1&b=&c=3")).toEqual({ a: "1", b: "", c: "3" }); +}); + +test("parses repeated keys (last one wins)", () => { + expect(parseQueryString("a=1&a=2")).toEqual({ a: "2" }); +}); diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..7603dbc78 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,20 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new Error("Input must be an array"); + } + + const result = {}; + + for (const item of items) { + if (result[item]) { + result[item] += 1; + } else { + result[item] = 1; + } + } + + return result; + +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..d11937802 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -23,12 +23,34 @@ const tally = require("./tally.js"); // 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"); + +// Empty array → empty object +test("tally on an empty array returns an empty object", () => { + expect(tally([])).toEqual({}); +}); + + +test("tally counts occurrences of items", () => { + expect(tally(["a", "a", "b", "c"])).toEqual({ + a: 2, + b: 1, + c: 1 + }); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("tally works for a single repeated item", () => { + expect(tally(["x", "x", "x"])).toEqual({ x: 3 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("tally throws an error for invalid input", () => { + expect(() => tally("not an array")).toThrow("Input must be an array"); +}); + + + diff --git a/Sprint-2/package.json b/Sprint-2/package.json index 6fb939824..0f6db50ec 100644 --- a/Sprint-2/package.json +++ b/Sprint-2/package.json @@ -6,6 +6,7 @@ "scripts": { "test": "jest" }, + "type": "module", "keywords": [], "author": "", @@ -13,4 +14,5 @@ "devDependencies": { "jest": "^29.7.0" } + } From 1903cda9a662296c0acbdad8c2585160143ddb16 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 22:24:45 +0000 Subject: [PATCH 10/14] created a test file for invert.js --- Sprint-2/interpret/invert.js | 15 ++++++++++++++- Sprint-2/interpret/invert.test.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Sprint-2/interpret/invert.test.js diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..19d9953bb 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -7,23 +7,36 @@ // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} function invert(obj) { + if (typeof obj !== "object" || obj === null || Array.isArray(obj)) { + throw new Error("Input must be a non-null object"); + } 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 } // b) What is the current return value when invert is called with { a: 1, b: 2 } +//Only the last value remains, so it returns: +//{ 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? +// as it is a built in method Object.entries returns an array of [key, value] pairs. +//It is needed so we can loop through both keys and values easily. // d) Explain why the current return value is different from the target output +//Because the code uses invertedObj.key (a literal property named "key") instead of using the variable key. +//It overwrites the same property instead of swapping keys and values // 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..5dea1191d --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,28 @@ +const invert = require("./invert"); + +test("inverts a simple object", () => { + expect(invert({ a: 1 })).toEqual({ "1": "a" }); +}); + +test("inverts multiple key/value pairs", () => { + expect(invert({ a: 1, b: 2 })).toEqual({ "1": "a", "2": "b" }); +}); + +test("inverts string values", () => { + expect(invert({ x: "apple", y: "banana" })).toEqual({ + apple: "x", + banana: "y" + }); +}); + +test("throws an error when input is not an object", () => { + expect(() => invert("not an object")).toThrow("Input must be a non-null object"); +}); + +test("throws an error for null", () => { + expect(() => invert(null)).toThrow("Input must be a non-null object"); +}); + +test("throws an error for arrays", () => { + expect(() => invert([1, 2, 3])).toThrow("Input must be a non-null object"); +}); From 57a03164ce4473bf3a352d14fcd7664af0b383e0 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 22:34:31 +0000 Subject: [PATCH 11/14] modified count-words.js --- Sprint-2/stretch/count-words.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 8e85d19d7..34d21e156 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -26,3 +26,33 @@ 3. Order the results to find out which word is the most common in the input */ +function countWords(str){ + str = str.toLowerCase(); + + // 2. Remove punctuation (anything that is not a letter, number, or space) + str = str.replace(/[^\w\s]/g, ''); + + // 3. Split the string into words + const words = str.split(/\s+/); + + // 4. Create an object to store word counts + const wordCounts = {}; + + // 5. Count each word + for (const word of words) { + if (word === '') continue; // skip empty strings (in case of multiple spaces) + if (wordCounts[word]) { + wordCounts[word] += 1; + } else { + wordCounts[word] = 1; + } + } + + // 6. Optional: Sort by frequency (most common first) + const sortedWordCounts = Object.fromEntries( + Object.entries(wordCounts).sort((a, b) => b[1] - a[1]) + ); + return sortedWordCounts; +}; + +console.log(countWords("You and me, and you!")); \ No newline at end of file From 23fc4938b3a8ab3d09bb51a8ba3abf5cc83aba66 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 23:05:09 +0000 Subject: [PATCH 12/14] added a test file to the till.js --- Sprint-2/stretch/mode.js | 21 ++++++++++++++------- Sprint-2/stretch/till.js | 11 +++++++++-- Sprint-2/stretch/till.test.js | 6 ++++++ 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 Sprint-2/stretch/till.test.js diff --git a/Sprint-2/stretch/mode.js b/Sprint-2/stretch/mode.js index 3f7609d79..3b46e6ba7 100644 --- a/Sprint-2/stretch/mode.js +++ b/Sprint-2/stretch/mode.js @@ -8,29 +8,36 @@ // refactor calculateMode by splitting up the code // into smaller functions using the stages above -function calculateMode(list) { - // track frequency of each value + +function trackFrequencies(list) { let freqs = new Map(); for (let num of list) { - if (typeof num !== "number") { - continue; - } + if (typeof num !== "number") continue; freqs.set(num, (freqs.get(num) || 0) + 1); } - // Find the value with the highest frequency + return freqs; +} + +function findMode(freqs) { let maxFreq = 0; let mode; + for (let [num, freq] of freqs) { if (freq > maxFreq) { - mode = num; maxFreq = freq; + mode = num; } } return maxFreq === 0 ? NaN : mode; } +function calculateMode(list) { + const freqs = trackFrequencies(list); + return findMode(freqs); +} + module.exports = calculateMode; diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 6a08532e7..f896aec44 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -8,10 +8,11 @@ function totalTill(till) { let total = 0; for (const [coin, quantity] of Object.entries(till)) { - total += coin * quantity; + const value = parseInt(coin); + total += value * quantity; } - return `£${total / 100}`; + return `£${(total / 100).toFixed(2)}`; } const till = { @@ -22,10 +23,16 @@ const till = { }; const totalAmount = totalTill(till); +module.exports = totalTill; + // a) What is the target output when totalTill is called with the till object +//£4.10 // b) Why do we need to use Object.entries inside the for...of loop in this function? +//Because Object.entries gives you both the coin and the quantity(which means key and value at once) in each loop. // c) What does coin * quantity evaluate to inside the for...of loop? +//"1p" * 10 → NaN, because "1p" is not a number. // d) Write a test for this function to check it works and then fix the implementation of totalTill +//the test is on another file. \ No newline at end of file diff --git a/Sprint-2/stretch/till.test.js b/Sprint-2/stretch/till.test.js new file mode 100644 index 000000000..389347a47 --- /dev/null +++ b/Sprint-2/stretch/till.test.js @@ -0,0 +1,6 @@ +const totalTill = require("./totalTill"); + +test("calculates the total in pounds", () => { + const till = { "1p": 10, "5p": 6, "50p": 4, "20p": 10 }; + expect(totalTill(till)).toBe("£4.40"); +}); From d0281fd58225cedde7e14d694bcb3963d40ba63e Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 23:13:21 +0000 Subject: [PATCH 13/14] test file has passed for till.js --- Sprint-2/stretch/till.js | 1 + Sprint-2/stretch/till.test.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index f896aec44..397a8efdc 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -22,6 +22,7 @@ const till = { "20p": 10, }; const totalAmount = totalTill(till); +console.log(totalAmount); module.exports = totalTill; diff --git a/Sprint-2/stretch/till.test.js b/Sprint-2/stretch/till.test.js index 389347a47..8e3c5f60a 100644 --- a/Sprint-2/stretch/till.test.js +++ b/Sprint-2/stretch/till.test.js @@ -1,6 +1,6 @@ -const totalTill = require("./totalTill"); +const totalTill = require("./till"); test("calculates the total in pounds", () => { const till = { "1p": 10, "5p": 6, "50p": 4, "20p": 10 }; expect(totalTill(till)).toBe("£4.40"); -}); +}); From 6d3cd1ab5ba8b3c47dbcc589a8e8ec10ffb5d825 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 1 Dec 2025 23:23:58 +0000 Subject: [PATCH 14/14] modified querystring.js --- Sprint-2/implement/querystring.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 4ea0244e9..ce7b9174b 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -17,9 +17,8 @@ function parseQueryString(queryString) { const value = pair.substring(idx + 1); queryParams[key] = value; } - - return queryParams; } +return queryParams; } module.exports = parseQueryString;