Skip to content

Commit 36695b5

Browse files
authored
Merge branch 'main' into sprint-1
2 parents 4359456 + d4189cd commit 36695b5

10 files changed

Lines changed: 179 additions & 24 deletions

File tree

‎Sprint-1/fix/median.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Start by running the tests for this function
33
// If you're in the Sprint-1 directory, you can run `npm test -- fix` to run the tests in the fix directory
44

5-
// Hint: Please consider scenarios when 'list' doesn't have numbers (the function is expected to return null)
6-
// or 'list' has mixed values (the function is expected to sort only numbers).
5+
// Hint: Please consider scenarios when 'list' isn't an array, is empty,
6+
// or contains values that aren't numbers (the function is expected to throw - see the tests).
77

88
function calculateMedian(list) {
99
// Check that the input is an array
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Don't change this function.
2+
function calculateMedian(list) {
3+
if (!Array.isArray(list)) {
4+
throw new Error("calculateMedian requires an array of numbers");
5+
}
6+
if (list.length === 0) {
7+
throw new Error("calculateMedian requires a non-empty array");
8+
}
9+
for (const item of list) {
10+
if (typeof item !== "number") {
11+
throw new Error("calculateMedian requires an array of numbers");
12+
}
13+
}
14+
const middleIndex = Math.floor(list.length / 2);
15+
const sorted = [...list].sort((a, b) => a - b);
16+
if (sorted.length % 2 === 0) {
17+
return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
18+
}
19+
return sorted[middleIndex];
20+
}
21+
22+
// Implement this function. See describe-median.test.js for the acceptance criteria.
23+
function describeMedian(list) {}
24+
25+
module.exports = describeMedian;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* Describe the median, or explain why there isn't one
2+
3+
calculateMedian is given to you at the top of describe-median.js. It throws
4+
when it can't calculate a median. Don't change it.
5+
6+
Implement describeMedian, which calls calculateMedian and returns a sentence
7+
instead of crashing.
8+
9+
E.g. describeMedian([1, 2, 3]), target output: "The median is 2"
10+
E.g. describeMedian([]), target output: "Could not calculate a median: calculateMedian requires a non-empty array"
11+
12+
You'll need a try/catch block for this. The catch block must use the error's
13+
message, so the caller can see what went wrong.
14+
*/
15+
16+
const describeMedian = require("./describe-median.js");
17+
18+
// Acceptance criteria:
19+
20+
// Given an array of numbers
21+
// When passed to describeMedian
22+
// Then it should return "The median is " followed by the median
23+
// Delete this test.todo and replace it with a test.
24+
test.todo('given [1, 2, 3], returns "The median is 2"');
25+
26+
// Given an empty array
27+
// When passed to describeMedian
28+
// Then it should return "Could not calculate a median: calculateMedian requires a non-empty array"
29+
30+
// Given something that isn't an array of numbers, e.g. "banana"
31+
// When passed to describeMedian
32+
// Then it should return "Could not calculate a median: calculateMedian requires an array of numbers"

‎Sprint-1/implement/mean.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function calculateMean(list) {}
2+
3+
module.exports = calculateMean;

‎Sprint-1/implement/mean.test.js‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* Calculate the mean of an array of numbers
2+
3+
In this kata, you will need to implement a function that calculates the mean of an array of numbers.
4+
5+
E.g. calculateMean([1, 2, 6]), target output: 3
6+
E.g. calculateMean([]) throws Error("calculateMean requires a non-empty array")
7+
E.g. calculateMean("banana") throws Error("calculateMean requires an array of numbers")
8+
9+
There is no mean of an empty array, and a string isn't an array of numbers, so
10+
calculateMean should throw rather than return a value. This is the same problem
11+
calculateMedian solves in the prep and in the fix directory.
12+
13+
You should implement this function in mean.js, and add tests for it in this file.
14+
15+
We have set things up already so that this file can see your function from the other file.
16+
*/
17+
18+
const calculateMean = require("./mean.js");
19+
20+
// Acceptance criteria:
21+
22+
// Given an array of numbers
23+
// When passed to calculateMean
24+
// Then it should return their mean
25+
// Delete this test.todo and replace it with a test.
26+
test.todo("given [1, 2, 6], returns 3");
27+
28+
// Given an array with a single number
29+
// When passed to calculateMean
30+
// Then it should return that number
31+
32+
// Given an array containing negative or decimal numbers
33+
// When passed to calculateMean
34+
// Then it should return the correct mean
35+
36+
// Given an empty array
37+
// When passed to calculateMean
38+
// Then it should throw Error("calculateMean requires a non-empty array")
39+
40+
// Given a value that isn't an array, e.g. "banana", 42, null or {}
41+
// When passed to calculateMean
42+
// Then it should throw Error("calculateMean requires an array of numbers")
43+
44+
// Given no argument at all
45+
// When passed to calculateMean
46+
// Then it should throw Error("calculateMean requires an array of numbers")
47+
48+
// Given an array containing a non-number value, e.g. [1, "2", 3]
49+
// When passed to calculateMean
50+
// Then it should throw Error("calculateMean requires an array of numbers")

‎Sprint-1/readme.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Here is a recommended order:
3131
1. `max.test.js`
3232
2. `sum.test.js`
3333
3. `dedupe.test.js`
34+
4. `mean.test.js`
35+
5. `describe-median.test.js`
3436

3537
Again, you can run just the test for the `implement` directory if you're in the `Sprint-1` directory by running `npm test -- implement`.
3638

‎Sprint-2/implement/contains.test.js‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ as the object contains a key of 'a'
99
1010
E.g. contains({a: 1, b: 2}, 'c') // returns false
1111
as the object doesn't contains a key of 'c'
12+
13+
E.g. contains([1, 2, 3], 'a') throws Error("contains requires an object")
14+
as an array isn't an object
1215
*/
1316

1417
// Acceptance criteria:
@@ -30,6 +33,8 @@ test.todo("contains on empty object returns false");
3033
// When passed to contains with a non-existent property name
3134
// Then it should return false
3235

33-
// Given invalid parameters like an array
36+
// Given a value that isn't an object - an array, a string, a number,
37+
// null, or no argument at all
3438
// When passed to contains
35-
// Then it should return false or throw an error
39+
// Then it should throw Error("contains requires an object")
40+
// (careful: typeof [] and typeof null are both "object")

‎Sprint-2/implement/tally.test.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ test.todo("tally on an empty array returns an empty object");
2929
// When passed to tally
3030
// Then it should return counts for each unique item
3131

32-
// Given an invalid input like a string
32+
// Given an invalid input like a string, a number, or no argument at all
3333
// When passed to tally
34-
// Then it should throw an error
34+
// Then it should throw Error("tally requires an array")

‎Sprint-2/stretch/mode.js‎

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
1-
// You are given an implementation of calculateMode
1+
// You are given a working implementation of calculateMode.
2+
// Run the tests in mode.test.js before you start: they all pass.
23

3-
// calculateMode's implementation can be broken down into two stages:
4+
// calculateMode's implementation can be broken down into three stages:
45

5-
// Stage 1. One part of the code tracks the frequency of each value
6-
// Stage 2. The other part finds the value with the highest frequency
6+
// Stage 1. Check the input is a non-empty array of numbers, and throw if not
7+
// Stage 2. Track the frequency of each value
8+
// Stage 3. Find the value with the highest frequency
79

8-
// refactor calculateMode by splitting up the code
9-
// into smaller functions using the stages above
10+
// Refactor calculateMode by moving each stage into its own function,
11+
// then calling those functions from calculateMode.
12+
13+
// The tests must still pass after your refactor. Run them again to check.
1014

1115
function calculateMode(list) {
16+
// check the input is a non-empty array of numbers
17+
if (!Array.isArray(list)) {
18+
throw new Error("calculateMode requires an array of numbers");
19+
}
20+
if (list.length === 0) {
21+
throw new Error("calculateMode requires a non-empty array");
22+
}
23+
for (const item of list) {
24+
if (typeof item !== "number") {
25+
throw new Error("calculateMode requires an array of numbers");
26+
}
27+
}
28+
1229
// track frequency of each value
1330
let freqs = new Map();
1431

1532
for (let num of list) {
16-
if (typeof num !== "number") {
17-
continue;
18-
}
19-
2033
freqs.set(num, (freqs.get(num) || 0) + 1);
2134
}
2235

@@ -30,7 +43,7 @@ function calculateMode(list) {
3043
}
3144
}
3245

33-
return maxFreq === 0 ? NaN : mode;
46+
return mode;
3447
}
3548

3649
module.exports = calculateMode;

‎Sprint-2/stretch/mode.test.js‎

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Don't change this file. The tests check your refactored calculateMode still behaves the same.
2+
13
const calculateMode = require("./mode.js");
24

35
// Acceptance criteria for calculateMode function
@@ -6,10 +8,15 @@ const calculateMode = require("./mode.js");
68
// When calculateMode is called on the array
79
// Then it should return the number that appears most frequently in the array
810

9-
// Example:
10-
// Given [2,4,1,2,3,2,1]
11-
// When calculateMode is called on [2,4,1,2,3,2,1]
12-
// Then it should return 2 */
11+
// E.g. calculateMode([2, 4, 1, 2, 3, 2, 1]) returns 2
12+
13+
// Given an empty array
14+
// When calculateMode is called on the array
15+
// Then it should throw Error("calculateMode requires a non-empty array")
16+
17+
// Given something that isn't an array of numbers, e.g. "banana" or [1, "2", 3]
18+
// When calculateMode is called on it
19+
// Then it should throw Error("calculateMode requires an array of numbers")
1320

1421
describe("calculateMode()", () => {
1522
test("returns the most frequent number in an array", () => {
@@ -24,9 +31,27 @@ describe("calculateMode()", () => {
2431
expect(calculateMode(nums)).toEqual(2);
2532
});
2633

27-
test("ignores non-number values", () => {
28-
const nums = [1, 3, "2", 2, 3, null];
34+
test("throws when the array contains a non-number", () => {
35+
expect(() => calculateMode([1, 3, "2", 2, 3, null])).toThrow(
36+
new Error("calculateMode requires an array of numbers")
37+
);
38+
});
39+
40+
test("throws when given something that isn't an array", () => {
41+
expect(() => calculateMode("banana")).toThrow(
42+
new Error("calculateMode requires an array of numbers")
43+
);
44+
});
45+
46+
test("throws when given no argument", () => {
47+
expect(() => calculateMode()).toThrow(
48+
new Error("calculateMode requires an array of numbers")
49+
);
50+
});
2951

30-
expect(calculateMode(nums)).toEqual(3);
52+
test("throws when given an empty array", () => {
53+
expect(() => calculateMode([])).toThrow(
54+
new Error("calculateMode requires a non-empty array")
55+
);
3156
});
3257
});

0 commit comments

Comments
 (0)