Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Sprint-1/fix/median.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Start by running the tests for this function
// If you're in the Sprint-1 directory, you can run `npm test -- fix` to run the tests in the fix directory

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

function calculateMedian(list) {
const middleIndex = Math.floor(list.length / 2);
Expand Down
134 changes: 101 additions & 33 deletions Sprint-1/fix/median.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,112 @@
const calculateMedian = require("./median.js");

describe("calculateMedian", () => {
[
{ input: [1, 2, 3], expected: 2 },
{ input: [1, 2, 3, 4, 5], expected: 3 },
{ input: [1, 2, 3, 4], expected: 2.5 },
{ input: [1, 2, 3, 4, 5, 6], expected: 3.5 },
].forEach(({ input, expected }) =>
it(`returns the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
);

[
{ input: [3, 1, 2], expected: 2 },
{ input: [5, 1, 3, 4, 2], expected: 3 },
{ input: [4, 2, 1, 3], expected: 2.5 },
{ input: [6, 1, 5, 3, 2, 4], expected: 3.5 },
{ input: [110, 20, 0], expected: 20 },
{ input: [6, -2, 2, 12, 14], expected: 6 },
].forEach(({ input, expected }) =>
it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
);
it("returns the median for [1, 2, 3]", () => {
expect(calculateMedian([1, 2, 3])).toEqual(2);
});

it("returns the median for [1, 2, 3, 4, 5]", () => {
expect(calculateMedian([1, 2, 3, 4, 5])).toEqual(3);
});

it("returns the median for [1, 2, 3, 4]", () => {
expect(calculateMedian([1, 2, 3, 4])).toEqual(2.5);
});

it("returns the median for [1, 2, 3, 4, 5, 6]", () => {
expect(calculateMedian([1, 2, 3, 4, 5, 6])).toEqual(3.5);
});

it("returns the correct median for unsorted array [3, 1, 2]", () => {
expect(calculateMedian([3, 1, 2])).toEqual(2);
});

it("returns the correct median for unsorted array [5, 1, 3, 4, 2]", () => {
expect(calculateMedian([5, 1, 3, 4, 2])).toEqual(3);
});

it("returns the correct median for unsorted array [4, 2, 1, 3]", () => {
expect(calculateMedian([4, 2, 1, 3])).toEqual(2.5);
});

it("returns the correct median for unsorted array [6, 1, 5, 3, 2, 4]", () => {
expect(calculateMedian([6, 1, 5, 3, 2, 4])).toEqual(3.5);
});

it("returns the correct median for unsorted array [110, 20, 0]", () => {
expect(calculateMedian([110, 20, 0])).toEqual(20);
});

it("returns the correct median for unsorted array [6, -2, 2, 12, 14]", () => {
expect(calculateMedian([6, -2, 2, 12, 14])).toEqual(6);
});

it("doesn't modify the input array [3, 1, 2]", () => {
const list = [3, 1, 2];
calculateMedian(list);
expect(list).toEqual([3, 1, 2]);
});

[ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val =>
it(`returns null for non-numeric array (${val})`, () => expect(calculateMedian(val)).toBe(null))
);

[
{ input: [1, 2, "3", null, undefined, 4], expected: 2 },
{ input: ["apple", 1, 2, 3, "banana", 4], expected: 2.5 },
{ input: [1, "2", 3, "4", 5], expected: 3 },
{ input: [1, "apple", 2, null, 3, undefined, 4], expected: 2.5 },
{ input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 },
{ input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 },
].forEach(({ input, expected }) =>
it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
);
// There is no median of an empty array, so calculateMedian should throw
it("throws when given an empty array", () => {
expect(() => calculateMedian([])).toThrow(
new Error("calculateMedian requires a non-empty array")
);
});

// Input that isn't an array should throw
it("throws when given a string", () => {
expect(() => calculateMedian("banana")).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws when given a number", () => {
expect(() => calculateMedian(123)).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws when given null", () => {
expect(() => calculateMedian(null)).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws when given an object", () => {
expect(() => calculateMedian({})).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws when called with no argument", () => {
expect(() => calculateMedian()).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

// Arrays containing any non-number value should throw, rather than filtering them out
it("throws for an array of strings", () => {
expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws for an array mixing numbers and strings", () => {
expect(() => calculateMedian([1, "2", 3, "4", 5])).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws for an array containing null", () => {
expect(() => calculateMedian([1, 2, null, 4])).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});

it("throws for an array containing undefined", () => {
expect(() => calculateMedian([3, 1, undefined, 2])).toThrow(
new Error("calculateMedian requires an array of numbers")
);
});
});
25 changes: 25 additions & 0 deletions Sprint-1/implement/describe-median.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Don't change this function.
function calculateMedian(list) {
if (!Array.isArray(list)) {
throw new Error("calculateMedian requires an array of numbers");
}
if (list.length === 0) {
throw new Error("calculateMedian requires a non-empty array");
}
for (const item of list) {
if (typeof item !== "number") {
throw new Error("calculateMedian requires an array of numbers");
}
}
const middleIndex = Math.floor(list.length / 2);
const sorted = [...list].sort((a, b) => a - b);
if (sorted.length % 2 === 0) {
return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
}
return sorted[middleIndex];
}

// Implement this function. See describe-median.test.js for the acceptance criteria.
function describeMedian(list) {}

module.exports = describeMedian;
32 changes: 32 additions & 0 deletions Sprint-1/implement/describe-median.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* Describe the median, or explain why there isn't one

calculateMedian is given to you at the top of describe-median.js. It throws
when it can't calculate a median. Don't change it.

Implement describeMedian, which calls calculateMedian and returns a sentence
instead of crashing.

E.g. describeMedian([1, 2, 3]), target output: "The median is 2"
E.g. describeMedian([]), target output: "Could not calculate a median: calculateMedian requires a non-empty array"

You'll need a try/catch block for this. The catch block must use the error's
message, so the caller can see what went wrong.
*/

const describeMedian = require("./describe-median.js");

// Acceptance criteria:

// Given an array of numbers
// When passed to describeMedian
// Then it should return "The median is " followed by the median
// Delete this test.todo and replace it with a test.
test.todo('given [1, 2, 3], returns "The median is 2"');

// Given an empty array
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires a non-empty array"

// Given something that isn't an array of numbers, e.g. "banana"
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires an array of numbers"
10 changes: 5 additions & 5 deletions Sprint-1/implement/max.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
In this kata, you will need to implement a function that find the largest numerical element of an array.

E.g. max([30, 50, 10, 40]), target output: 50
E.g. max(['hey', 10, 'hi', 60, 10]), target output: 60 (sum ignores any non-numerical elements)
E.g. max(['hey', 10, 'hi', 60, 10]) throws Error("findMax requires an array of numbers") (max can't compare non-numerical elements, so it shouldn't guess)

You should implement this function in max.js, and add tests for it in this file.

Expand Down Expand Up @@ -34,10 +34,10 @@ test.todo("given an empty array, returns -Infinity");
// When passed to the max function
// Then it should return the largest decimal number

// Given an array with non-number values
// Given an array containing a value that isn't a number
// When passed to the max function
// Then it should return the max and ignore non-numeric values
// Then it should throw Error("findMax requires an array of numbers")

// Given an array with only non-number values
// Given something that isn't an array at all, such as "hey", 42 or no argument
// When passed to the max function
// Then it should return the least surprising value given how it behaves for all other inputs
// Then it should throw Error("findMax requires an array of numbers")
3 changes: 3 additions & 0 deletions Sprint-1/implement/mean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function calculateMean(list) {}

module.exports = calculateMean;
50 changes: 50 additions & 0 deletions Sprint-1/implement/mean.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* Calculate the mean of an array of numbers

In this kata, you will need to implement a function that calculates the mean of an array of numbers.

E.g. calculateMean([1, 2, 6]), target output: 3
E.g. calculateMean([]) throws Error("calculateMean requires a non-empty array")
E.g. calculateMean("banana") throws Error("calculateMean requires an array of numbers")

There is no mean of an empty array, and a string isn't an array of numbers, so
calculateMean should throw rather than return a value. This is the same problem
calculateMedian solves in the prep and in the fix directory.

You should implement this function in mean.js, and add tests for it in this file.

We have set things up already so that this file can see your function from the other file.
*/

const calculateMean = require("./mean.js");

// Acceptance criteria:

// Given an array of numbers
// When passed to calculateMean
// Then it should return their mean
// Delete this test.todo and replace it with a test.
test.todo("given [1, 2, 6], returns 3");

// Given an array with a single number
// When passed to calculateMean
// Then it should return that number

// Given an array containing negative or decimal numbers
// When passed to calculateMean
// Then it should return the correct mean

// Given an empty array
// When passed to calculateMean
// Then it should throw Error("calculateMean requires a non-empty array")

// Given a value that isn't an array, e.g. "banana", 42, null or {}
// When passed to calculateMean
// Then it should throw Error("calculateMean requires an array of numbers")

// Given no argument at all
// When passed to calculateMean
// Then it should throw Error("calculateMean requires an array of numbers")

// Given an array containing a non-number value, e.g. [1, "2", 3]
// When passed to calculateMean
// Then it should throw Error("calculateMean requires an array of numbers")
10 changes: 5 additions & 5 deletions Sprint-1/implement/sum.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
In this kata, you will need to implement a function that sums the numerical elements of an array

E.g. sum([10, 20, 30]), target output: 60
E.g. sum(['hey', 10, 'hi', 60, 10]), target output: 80 (ignore any non-numerical elements)
E.g. sum(['hey', 10, 'hi', 60, 10]) throws Error("sum requires an array of numbers") (sum can't add non-numerical elements, so it shouldn't guess)
*/

const sum = require("./sum.js");
Expand All @@ -27,10 +27,10 @@ test.todo("given an empty array, returns 0")
// When passed to the sum function
// Then it should return the correct total sum

// Given an array containing non-number values
// Given an array containing a value that isn't a number
// When passed to the sum function
// Then it should ignore the non-numerical values and return the sum of the numerical elements
// Then it should throw Error("sum requires an array of numbers")

// Given an array with only non-number values
// Given something that isn't an array at all, such as "hey", 42 or no argument
// When passed to the sum function
// Then it should return the least surprising value given how it behaves for all other inputs
// Then it should throw Error("sum requires an array of numbers")
2 changes: 2 additions & 0 deletions Sprint-1/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Here is a recommended order:
1. `max.test.js`
2. `sum.test.js`
3. `dedupe.test.js`
4. `mean.test.js`
5. `describe-median.test.js`

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

Expand Down