Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// 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

// Create an object that holds address details
const address = {
houseNumber: 42,
street: "Imaginary Road",
Expand All @@ -12,4 +11,5 @@ const address = {
postcode: "XYZ 123",
};

console.log(`My house number is ${address[0]}`);
// Access the houseNumber property using dot notation
console.log(`My house number is ${address.houseNumber}`);
22 changes: 20 additions & 2 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Predict and explain first...

// 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

// Create an object that holds author details
const author = {
firstName: "Zadie",
lastName: "Smith",
Expand All @@ -11,6 +11,24 @@ const author = {
alive: true,
};

for (const value of author) {
// Use Object.values() to get an array of all values, then loop over them
for (const value of Object.values(author)) {
console.log(value);
}

/*
## Explanation of the Fix

- Object.values(author) is a built-in function that takes an object and returns an array containing only the values. In our case it returns: ["Zadie", "Smith", "writer", 40, true]
- Since the result is now an array, for...of works correctly and goes through each value one by one.

## How to Test in the Terminal
node author.js

Expected output:
Zadie
Smith
writer
40
true
*/
30 changes: 26 additions & 4 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,36 @@

// 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?

// Create an object that holds recipe details
const recipe = {
title: "bruschetta",
serves: 2,
ingredients: ["olive oil", "tomatoes", "salt", "pepper"],
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
// Log the title and how many it serves
console.log(`${recipe.title} serves ${recipe.serves}`);

// Log each ingredient on a new line using a loop
for (const ingredient of recipe.ingredients) {
console.log(ingredient);
}

/*
## Brief Explanation

- recipe.ingredients is an array (a numbered list) containing four items.
- for...of works on arrays, so it goes through each item one by one.
- Each time through the loop, the variable ingredient holds the current item, and console.log prints it on its own line.

## How to Test
node recipe.js

Expected output:
bruschetta serves 2
olive oil
tomatoes
salt
pepper
*/
11 changes: 10 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
function contains() {}
// Check if an object contains a specific property
function contains(object, propertyName) {
// If the input is not a valid object or is an array, return false
if (typeof object !== "object" || object === null || Array.isArray(object)) {
return false;
}

// Use hasOwnProperty to check if the key exists in the object
return object.hasOwnProperty(propertyName);
}

module.exports = contains;
15 changes: 13 additions & 2 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
function createLookup() {
// implementation here
// Take an array of pairs and return a lookup object
function createLookup(pairs) {
// Create an empty object to store the results
const lookup = {};

// Loop through each pair in the array
for (const pair of pairs) {
// pair[0] is the key (country code), pair[1] is the value (currency code)
lookup[pair[0]] = pair[1];
}

// Return the completed lookup object
return lookup;
}

module.exports = createLookup;
21 changes: 19 additions & 2 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
// Parse a query string into an object of key-value pairs
function parseQueryString(queryString) {
// Create an empty object to store the results
const queryParams = {};

// If the input is empty, return the empty object
if (queryString.length === 0) {
return queryParams;
}

// Split the string by "&" to get each key=value pair
const keyValuePairs = queryString.split("&");

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
queryParams[key] = value;
// Find the position of the FIRST "=" only
const firstEqualIndex = pair.indexOf("=");

// If there is no "=", the whole pair is the key with an empty value
if (firstEqualIndex === -1) {
queryParams[pair] = "";
} else {
// Everything before the first "=" is the key
const key = pair.slice(0, firstEqualIndex);
// Everything after the first "=" is the value (may contain more "=" signs)
const value = pair.slice(firstEqualIndex + 1);
queryParams[key] = value;
}
}

return queryParams;
Expand Down
21 changes: 20 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
function tally() {}
// Count the frequency of each item in an array
function tally(items) {
// If the input is not an array, throw an error
if (!Array.isArray(items)) {
throw new Error("Input must be an array");
}

// Create an empty object to store the counts
const counts = {};

// Loop through each item in the array
for (const item of items) {
// If this item already exists in counts, add 1 to it
// If it does not exist yet, start at 1
counts[item] = (counts[item] || 0) + 1;
}

// Return the object with all the counts
return counts;
}

module.exports = tally;
44 changes: 30 additions & 14 deletions Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,45 @@
// Let's define how invert should work

// Given an object
// When invert is passed this object
// Then it should swap the keys and values in the object

// E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"}
// E.g. invert({x: 10, y: 20}), target output: {"10": "x", "20": "y"}

/*
--- Answers to the Interpret Questions ---

a) What is the return value of invert({a: 1}) in the old broken code?
Answer: It returned { key: 1 } because dot notation (.key) creates a literal string key named "key".

b) What is the return value of invert({a: 1, b: 2}) in the old broken code?
Answer: It returned { key: 2 } because the literal property "key" is overwritten in the second loop iteration.

c) What is the target return value of invert({a: 1, b: 2})?
Answer: The target return value is { "1": "a", "2": "b" }.

c-continued) What does Object.entries do? Why is it needed here?
Answer: Object.entries(obj) converts the object into an array of key-value pairs, like [["a", 1], ["b", 2]]. It is needed because we cannot use a 'for...of' loop directly on a standard object.

d) Why is the current return value different from the target?
Answer: Because the old code used invertedObj.key (a hardcoded key name) instead of assigning the dynamic value as the new key.

e) How can you fix it?
Answer: By using bracket notation to set the 'value' as the new dynamic key, and assigning the 'key' as its value: invertedObj[value] = key;
*/

// Swap keys and values in an object
function invert(obj) {
// Create an empty object to store the swapped pairs
const invertedObj = {};

// Loop through each [key, value] pair in the original object
for (const [key, value] of Object.entries(obj)) {
invertedObj.key = value;
// Use the VALUE as the new key, and the KEY as the new value
invertedObj[value] = key;
}

// Return the inverted object
return invertedObj;
}

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

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

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

// c) What does Object.entries return? Why is it needed in this program?

// d) Explain why the current return value is different from the target output

// e) Fix the implementation of invert (and write tests to prove it's fixed!)
module.exports = invert;
82 changes: 71 additions & 11 deletions Sprint-2/stretch/count-words.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,85 @@
Write a function called countWords that
- takes a string as an argument
- returns an object where
- the keys are the words from the string and
- the values are the number of times the word appears in the string
- the keys are the words from the string and
- the values are the number of times the word appears in the string

Example
If we call countWords like this:

countWords("you and me and you") then the target output is { you: 2, and: 2, me: 1 }

To complete this exercise you should understand
- Strings and string manipulation
- Loops
- Comparison inside if statements
- Setting values on an object
## Advanced challenges

## Advanced challenges
1. Remove all of the punctuation (e.g. ".", ",", "!", "?") to tidy up the results
2. Ignore the case of the words to find more unique words. e.g. (A === a, Hello === hello)
3. Order the results to find out which word is the most common in the input
*/

// Count how many times each word appears in a string
function countWords(str) {
// If the string is empty, return an empty object
if (str.trim().length === 0) {
return {};
}

// Advanced challenge 1: Remove punctuation marks from the string
const cleaned = str.replace(/[.,!?;:'"()]/g, "");

// Advanced challenge 2: Convert the whole string to lowercase so "Hello" and "hello" count as the same word
const lowered = cleaned.toLowerCase();

// Split the string into an array of individual words (split by spaces)
const words = lowered.split(" ");

// Create an empty object to store the word counts
const counts = {};

// Loop through each word in the array
for (const word of words) {
// Skip empty strings that may result from extra spaces
if (word === "") {
continue;
}

// If the word already exists in counts, add 1; otherwise start at 1
counts[word] = (counts[word] || 0) + 1;
}

// Advanced challenge 3: Sort words by count (most common first)
const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]);

// Convert the sorted array back into an object
const sortedCounts = {};
for (const [word, count] of sorted) {
sortedCounts[word] = count;
}

return sortedCounts;
}

// Test the function
console.log(countWords("you and me and you"));
console.log(countWords("Hello hello world! World."));
console.log(countWords("the cat sat on the mat, the cat sat"));

/*
## Brief Explanation

- `str.replace(/[.,!?;:'"()]/g, "")` removes all punctuation. The `/g` flag means "find all matches, not just the first one".
- `.toLowerCase()` converts everything to lowercase so "Hello" and "hello" are treated as the same word.
- `.split(" ")` breaks the string into an array at every space.
- The `for` loop counts each word using the same pattern as the `tally` function you already completed.
- `Object.entries(counts).sort((a, b) => b[1] - a[1])` sorts the entries by count from highest to lowest.

## How to Test

node count-words.js

1. Remove all of the punctuation (e.g. ".", ",", "!", "?") to tidy up the results

2. Ignore the case of the words to find more unique words. e.g. (A === a, Hello === hello)
Expected output:

3. Order the results to find out which word is the most common in the input
{ you: 2, and: 2, me: 1 }
{ hello: 2, world: 2 }
{ the: 3, cat: 2, sat: 2, on: 1, mat: 1 }
*/
Loading
Loading