Skip to content

ZA-ITP-May-2025 | Christian Mayamba | Module-Data-Groups | Week 2 #699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Predict and explain first...
// The variable 'address' is an object, not an array,
// so the code won't give the house number.

// This code should log out the houseNumber from the address object
// but it isn't working...
Expand All @@ -12,4 +14,4 @@ const address = {
postcode: "XYZ 123",
};

console.log(`My house number is ${address[0]}`);
console.log(`My house number is ${address.houseNumber}`);
7 changes: 5 additions & 2 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Predict and explain first...
// - I predict that it won't work, because the variable 'value' isn't defined.

// 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
// - I was wrong, the error that it gives is that the variable 'author' is not iterable.
// Checking for a solution...

const author = {
firstName: "Zadie",
Expand All @@ -11,6 +14,6 @@ const author = {
alive: true,
};

for (const value of author) {
console.log(value);
for (const key in author) {
console.log(author[key]);
}
14 changes: 12 additions & 2 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
// Predict and explain first...
// - The program will give the recipe title and serves,
// but the ingredients will be undefined
// because it calls the whole object at the end, instead of the key 'ingredients' of 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?
// - First, I was wrong. The ingredients came out as 'object', not undefined.
// - To fix it, I removed the object recipe from the first console.log,
// and I used forEach to go through the 'recipe.ingredients' array and list all elements,
// each on a new line.

const recipe = {
title: "bruschetta",
Expand All @@ -11,5 +18,8 @@ const recipe = {
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
ingredients:`);

recipe.ingredients.forEach((element) => {
console.log(element);
});
21 changes: 20 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
function contains() {}
function contains(object1, prop1) {
if (
typeof object1 !== "object" ||
object1 === null ||
Array.isArray(object1)
) {
console.log("Error: object1 must be a non-null object and not an array.");
return false;
}

if (prop1 in object1) {
return true;
} else {
return false;
}
}

const myObject = [15, 20, 30];

console.log(contains(myObject, "test2"));

module.exports = contains;
45 changes: 44 additions & 1 deletion Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,59 @@ 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("contains on empty object returns false", () => {
const object = {};

expect(contains(object, "cat")).toBe(false);
});

// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true
test("Given object with properties, should return true if the property name is in the object", () => {
const object1 = {
test1: 56,
test2: "cat",
test3: "dog",
};
expect(contains(object1, "test2")).toBe(true);
});

// Given an object with properties
// When passed to contains with a non-existent property name
// Then it should return false
test("When the property name isn't in the object, should return false", () => {
const object2 = {
test4: 52,
test5: "mango",
test6: "banana",
};
expect(contains(object2, "test7")).toBe(false);
});

// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
test("Given invalid parameters, should return false or an error", () => {
const array1 = ["duo", "mono", 105];

expect(contains(array1, "mono")).toBe(false);
});

//Given a string as an object
//When passed to contains
//Then it should return false
test("Given a string as an object, should return false or an error", () => {
const string1 = "hello";

expect(contains(string1, "mono")).toBe(false);
});

//Given an object that's 'null'
//When passed to contains
//Then it should return false
test("Given a null object, should return false or an error", () => {
const object3 = null;

expect(contains(object3, "mono")).toBe(false);
});
14 changes: 12 additions & 2 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
function createLookup() {
// implementation here
function createLookup(nestedArray) {
let finalObject = {};

nestedArray.forEach((pair) => {
const key = pair[0];
const value = pair[1];
finalObject[key] = value;
});

return finalObject;
}

console.log(createLookup([["NG", "Naira"]]));

module.exports = createLookup;
8 changes: 7 additions & 1 deletion Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
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", () => {
testArray1 = [
["US", "USD"],
["DRC", "CDF"],
];
expect(createLookup(testArray1)).toStrictEqual({ US: "USD", DRC: "CDF" });
});

/*

Expand Down
3 changes: 2 additions & 1 deletion Sprint-2/implement/querystring.js
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

In the real world, URLs are usually encoded with percent encoding to represent special characters. In URL, & can be used as a separator (key=value&key=value...) or special character within a key or value. if we were to use & as a special character, we need to encode it.

Can you refactor the code so that parseQueryString("a%25b=c%26d") results in { "a%b": "c&d" }?
FYI, %25 is same as %, %26 is same as &

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ function parseQueryString(queryString) {
const keyValuePairs = queryString.split("&");

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
const [key, ...rest] = pair.split("=");
const value = rest.join("=");
queryParams[key] = value;
}

Expand Down
20 changes: 18 additions & 2 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@
// 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 an empty string", () => {
expect(parseQueryString("")).toEqual({});
});

test("parses querystring with missing value", () => {
expect(parseQueryString("key=")).toEqual({ key: "" });
});

test("parses querystring with no equal sign", () => {
expect(parseQueryString("lonely")).toStrictEqual({ lonely: "" });
});

test("parses querystring with repeated values", () => {
expect(parseQueryString("a=1&a=2")).toEqual({ a: "2" });
});
18 changes: 17 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
function tally() {}
function tally(array) {
if (!Array.isArray(array)) {
throw new Error("Input must be an array");
}

const result = {};

for (const item of array) {
if (result[item]) {
result[item] = result[item] + 1;
} else {
result[item] = 1;
}
}

Comment on lines +8 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done! As a challenge, can you refactor the code with an array method and ternary operator so the code can be more simple and concise?

return result;
}

module.exports = tally;
17 changes: 16 additions & 1 deletion Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,27 @@ 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");
test("tally on an empty array returns an empty object", () => {
const testArray = [];

expect(tally(testArray)).toStrictEqual({});
});

// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item
test("tally on an array with duplicate items returns counts for each item", () => {
const testArray1 = ["a", "a", "b", "c"];

expect(tally(testArray1)).toStrictEqual({ 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 on an invalid input throws an error", () => {
const testArray2 = "mango";
const invalidInput = () => tally(testArray2);

expect(invalidInput).toThrow("Input must be an array");
});
16 changes: 15 additions & 1 deletion Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,34 @@ function invert(obj) {
const invertedObj = {};

for (const [key, value] of Object.entries(obj)) {
invertedObj.key = value;
invertedObj[value] = key;
}

return invertedObj;
}

const testObj = { a: 1, b: 2 };
console.log(invert(testObj));

module.exports = invert;

// a) What is the current return value when invert is called with { a : 1 }
// - The current return value is { key: 1 }

// b) What is the current return value when invert is called with { a: 1, b: 2 }
// - The current return value is { key: 2 }

// c) What is the target return value when invert is called with {a : 1, b: 2}
// - The target return value is {"1": "a", "2": "b"}

// c) What does Object.entries return? Why is it needed in this program?
// - Object.entries returns an array of arrays,
// where each inner array represents a [key, value] pair from the input object.
// - It is needed to transform the given object into a nested array of the key-value pairs.
// Then use that array to invert the object's key and value.

// d) Explain why the current return value is different from the target output
// - Because this line 13 creates a property named "key",
// instead of inverting the original key and value.

// e) Fix the implementation of invert (and write tests to prove it's fixed!)
21 changes: 21 additions & 0 deletions Sprint-2/interpret/invert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const objectInvert = require("./invert.js");

test("Inverting an object with one key and value", () => {
const test1 = { a: 1 };
expect(objectInvert(test1)).toEqual({ 1: "a" });
});

test("Inverting an object with two keys and values", () => {
const test2 = { a: 1, b: 2 };
expect(objectInvert(test2)).toEqual({ 1: "a", 2: "b" });
});

test("Inverting an empty object", () => {
const test3 = {};
expect(objectInvert(test3)).toEqual({});
});

test("Inverting an object with duplicate values", () => {
const test4 = { a: 1, b: 1, c: 2 };
expect(objectInvert(test4)).toEqual({ 1: "b", 2: "c" });
});