๐พ Grouping data
Learning Objectives
In programming, we often have related pieces of data.
Let’s consider a list of prices in a bill:
4.6, 5.03, 7.99, 8.01
limitations of many variables
We can store this list of prices in a JavaScript program by declaring multiple variables:
const price0 = 4.6;
const price1 = 5.03;
const price2 = 7.99;
const price3 = 8.01;
Each identifier is the word price with a numerical suffix to indicate its position in the list. However, this is undoubtedly the wrong approach.
- If the number of items in the bill is huge, we must keep declaring new variables.
- If the number of items changes, we must reassign the values of variables so they’re in the correct order, and change any place we’re using the variables to know about the new one.
- If we do mutliple things to all of the values (say we have one loop adding them, and one loop printing them), we will need to change all of the places any time we add new values.
Instead we have to group the data together using a
๐ Arrays
Learning Objectives
In JavaScript, we can store data inside an
Instead of writing:
const item0 = 4.6;
const item1 = 5.03;
const item2 = 7.99;
const item3 = 8.01;
We can declare an array literal as follows:
const items = [4.6, 5.03, 7.99, 8.01];
Notice the identifier for the array is items. We chose to use the plural word items instead of the singular item, because arrays can store multiple pieces of information.
ordered data
๐ก
Recall
const volunteer = "Moussab";
The character "M" is at index 0, "o" is at index 1, and so on.
As with strings, arrays are also zero-indexed in a similar way:
const items = [4.6, 5.03, 7.99, 8.01];
So we can refer to the
| index | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| element | 4.6 | 5.03 | 7.99 | 8.01 |
In JavaScript, we can use square bracket notation to access specific elements in the array using an index.
items[0]; // evaluates to 4.6
items[1]; // evaluates to 5.03
items[2]; // evaluates to 7.99
// etc
๐ Calculating the mean
Learning Objectives
Let’s consider a problem where we calculate the mean of a list of numbers.
Given an array of numbers
When we call calculateMean with the array of numbers
Then we get the mean.
Let’s create a test to check its functionality. In your prep dir, touch mean.js && touch mean.test.js. Write the following test in the mean.test.js file.
test("calculates the mean of a list of numbers", () => {
const list = [3, 50, 7];
const currentOutput = calculateMean(list);
const targetOutput = 20;
expect(currentOutput).toBe(targetOutput); // 20 is (3 + 50 + 7) / 3
});
In this test, we’re checking we get a value of 20 by adding together 3 + 50 + 7 and then dividing by the number of items (3). We calculate the mean of a list of numbers by:
- summing all the numbers in the array
- dividing the sum by the length of the array
We can define a ๐ฏ sub-goal of calculating the sum of all numbers in the list.
โ Summation
Learning Objectives
๐ฏ Sub-goal: compute the sum of an array of numbers.
To sum a list we can start by creating a variable total with an initial value of 0.
We then need to repeatedly add each value in the list to our total.
function sumValues(list) {
let total = 0;
total += list[0]; // access a list element and add to total
total += list[1];
total += list[2];
total += list[3];
total += list[4];
return total;
}
sumValues([1, 2, 3, 4, 5]);
However, this approach is flawed.
๐ Iteration
Learning Objectives
To solve the sub-goal, we have to repeatedly add each number in the array to the total, one at a time. In programming, the process of repeating something is called iteration.
In programming, we can iterate by using a
In particular, we can use a for...of statement to sum the elements of the array.
function calculateMean(list) {
let total = 0;
for (const item of list) {
total += item;
}
}
๐ Calculating the median
Learning Objectives
Let’s define another problem.
We want to calculate the median value from an array of numbers.
Given an array of numbers in ascending order
When we call calculateMedian with this array
Then we get the median value.
We calculate the median of a list of numbers by finding the middle value in the list.
Let’s start with a test to check the return value of calculateMedian given an ordered list of numbers. In your prep dir, touch median.js && touch median.test.js. Write the following test in the median.test.js file.
test("calculates the median of a list of odd length", () => {
const list = [10, 20, 30, 50, 60];
const currentOutput = calculateMedian(list);
const targetOutput = 30;
expect(currentOutput).toBe(targetOutput);
});
๐จ Implementing calculateMedian
So we can implement calculateMedian.
We can summarise our approach as follows.
In code we can we can use splice to to get the middle item.
function calculateMedian(list) {
const middleIndex = Math.floor(list.length / 2);
const median = list.splice(middleIndex, 1)[0];
return median;
}
๐งฑ Assembling the parts
Learning Objectives
Now suppose we have a program where we use the functions we implemented earlier:
const salaries = [10, 20, 30, 40, 60, 80, 80];
const median = calculateMedian(salaries);
const mean = calculateMean(salaries);
console.log(`The median salary is ${median}`);
console.log(`The mean salary is ${mean}`);
Predict and explain what will get printed to the console when the code above runs.
Then run the code above on your local machine to check your prediction. Does your initial explanation now make sense?
(Note: you’ll have to declare the functions somewhere too)
๐ Finding the bug
In the code above, the median value is correct: however, the mean is incorrect.
We can add a log to the program to identify the origin of the bug.
| |
Run it
To understand why this bug occurs, we need to explore more concepts.
๐ค References
Learning Objectives
Arrays are stored by
Consider the following example,
const list = [10, 20, 30];
const copy = list;
copy.push(60, 70);
console.log(list);
console.log(copy);
Let’s break down what is happening in this program.
Play computer with the code above to step through the code and find out what happens when the code is executed.

- We make an array
[10, 20, 30]and store it somewhere in memory. listis assigned a reference to the location in memory containing[10, 20, 30]copyis assigned a reference pointing at the same location in memory aslist
At this stage in the program, list and copy point to the same location in memory.
pushfunction mutates (changes) the array thatcopypoints to.- prints out
list:[10, 20, 30, 60, 70] - prints out
copy:[10, 20, 30, 60, 70]
So as copy and list point to the same array.
If we mutate list then we’re mutating the same list that copy points to.
So the console output is the same.
| |
In the example above, salaries is assigned a reference on the first line.
Explain why calculateMedian and calculateMean both get access to the same array.
Shared reference
We can also check these variables share the same reference.
const list = [10, 20, 30];
const copy = list;
console.log(list === copy); // logs true
If we’re comparing 2 array variables with ===, then it will evaluate to true only if they have the same reference. === is comparing the references to the arrays, not the contents of arrays.
If we made two different arrays with the same contents, they would not be === equal:
const list = [10, 20, 30];
const copy = [10, 20, 30];
console.log(list === copy); // logs false
Value vs reference
In JavaScript, arrays and objects are reference types: everything else is a value type.๐
Passing by value
Use the tabs below to compare the effects of passing by reference and passing by value.
There are two different but similar implementations of pluralise - a function that appends an s to the end of its input.
Here pluralise is passed an array by reference.
lettersInAnArray is passed by reference. pluralise’s modification is visible here, because the same underlying storage was modified.
Step through the code to observe this behaviour:
Here pluralise is passed a string by value.
This means a copy of string’s value is passed to pluralise in the second tab. pluralise’s reassignment is not visible here, because a copy was made just for the function before the value was modified.
Step through the code to observe this behaviour:
๐ Mutation
Learning Objectives
Let’s take another look at our earlier implementation of calculateMedian:
function calculateMedian(list) {
const middleIndex = Math.floor(list.length / 2);
const median = list.splice(middleIndex, 1)[0];
return median;
}
const salaries = [10, 20, 30, 40, 60, 80, 80];
const median = calculateMedian(salaries);
// At this point, the array referenced by salaries has been mutated after calculateMedian(salaries), and a reference to the same array is given to calculateMean
const mean = calculateMean(salaries);
console.log(`The median salary is ${median}`);
console.log(`The mean salary is ${mean}`);
calculateMedian gets the middle value by calling splice. However, splice is a
When we call splice it does 2 things:
- removes the specified item from the list
- returns the removed item
splice modifies the array: however, calculateMean is also passed a reference to the same array too.
In other words,
calculateMedianmodifies the same array that is passed tocalculateMean.
Play computer with the example above. Pay careful attention to what happens when salaries is passed to calculateMedian
โ ๏ธ Side effects
Learning Objectives
Currently calculateMedian mutates its input - the array of numbers. This mutation is called a
In this case, the side effect has unintended consequences. We have introduced a
calculateMean return the wrong value. Both calculateMean and calculateMedian need access to the original salaries array. Therefore, we should take make sure we don’t mutate the array unless we really mean to.
Testing no mutation
We can add an additional assertion to the tests for calculateMedian to check it isn’t modifying the original input:
test("doesn't modify the input", () => {
const list = [1, 2, 3];
calculateMedian(list);
expect(list).toEqual([1, 2, 3]); // Note that the toEqual matcher checks the values inside arrays when comparing them - it doesn't use `===` on the arrays, we know that would always evaluate to false.
});
In this test, we don’t check the return value of calculateMedian. We assert that the input has the same contents as the original input. We can use the toEqual matcher to check the contents of the array referenced by the variable list.
Recall the current buggy implementation of calculateMedian:
function calculateMedian(list) {
const middleIndex = Math.floor(list.length / 2);
const median = list.splice(middleIndex, 1)[0];
return median;
}
We’ve established that we shouldn’t use splice to retrieve the median from the input array.
Fix the implementation of calculateMedian above so it no longer calls splice (which mutates the input), and instead gives the right answer without mutating the input.
๐ Implementing all the cases
Learning Objectives
Try writing a test case to check calculateMedian works in the case when it is passed an array of even length.
Use documentation to check how the median is computed in this case.
Once you’ve written your test case for calculateMedian, hopefully you see this implementation isn’t doing the right thing. Try implementing the functionality for this case.
Fail Fast Prep
๐ค๐ฝ FeedbackLearning Objectives
Introduction
Failing fast is crucial for identifying flaws and giving you a quick opportunity to change anything that is needed.
Embracing failure as a learning opportunity accelerates growth and adaptation and is a skill that makes you a more efficient professional.
Failing fast
๐ฏ Goal: Learn about failing fast (20 minutes)
- Read this piece that will introduce you to the concept of failing fast and how this can be put into practice by using the Agile framework.
- Watch this video about failure and how you learn and innovate.
Reflect on your experience of Failing Fast
๐ฏ Goal: Reflection on failing fast concept in your life (20 minutes)
Considering what you have learned regarding Failing Fast, think of an instance when you failed to achieve something you aimed for.
Write down about this event and reflect on it.
You can use the following questions to guide you.
- What did you learn from it?
- Did you try a different approach to achieve the same goal?
- Did you change the objective you were after?
- What would you have done differently?