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
15 changes: 12 additions & 3 deletions Sprint-1/fix/median.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@
// 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);
const median = list.splice(middleIndex, 1)[0];
return median;
if (!Array.isArray(list) || list.some((item) => typeof item !== "number")) {
throw new Error("calculateMedian requires an array of numbers");
}
if (list.length === 0) {
throw new Error("calculateMedian requires a non-empty array");
}
const sorted = [...list].sort((a, b) => a - b);
const middleIndex = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
}
return sorted[middleIndex];
}

module.exports = calculateMedian;
6 changes: 5 additions & 1 deletion Sprint-1/implement/dedupe.js
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
function dedupe() {}
function dedupe(list) {
return [...new Set(list)];
}

module.exports = dedupe;
17 changes: 16 additions & 1 deletion Sprint-1/implement/dedupe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,22 @@ E.g. dedupe([1, 2, 1]) returns [1, 2]
// Given an empty array
// When passed to the dedupe function
// Then it should return an empty array
test.todo("given an empty array, it returns an empty array");
test("given an empty array, it returns an empty array", () => {
expect(dedupe([])).toEqual([]);
});

test("given an array with no duplicates, returns a copy", () => {
const input = [1, 2, 3];
const result = dedupe(input);
expect(result).toEqual([1, 2, 3]);
expect(result).not.toBe(input);
});

test("removes duplicates preserving first occurrences", () => {
expect(dedupe(["a", "a", "a", "b", "b", "c"])).toEqual(["a", "b", "c"]);
expect(dedupe([5, 1, 1, 2, 3, 2, 5, 8])).toEqual([5, 1, 2, 3, 8]);
expect(dedupe([1, 2, 1])).toEqual([1, 2]);
});

// Given an array with no duplicates
// When passed to the dedupe function
Expand Down
8 changes: 7 additions & 1 deletion Sprint-1/implement/describe-median.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ function calculateMedian(list) {
}

// Implement this function. See describe-median.test.js for the acceptance criteria.
function describeMedian(list) {}
function describeMedian(list) {
try {
return `The median is ${calculateMedian(list)}`;
} catch (error) {
return `Could not calculate a median: ${error.message}`;
}
}

module.exports = describeMedian;
16 changes: 15 additions & 1 deletion Sprint-1/implement/describe-median.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,21 @@ const describeMedian = require("./describe-median.js");
// 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"');
test('given [1, 2, 3], returns "The median is 2"', () => {
expect(describeMedian([1, 2, 3])).toBe("The median is 2");
});

test("given an empty array, explains why", () => {
expect(describeMedian([])).toBe(
"Could not calculate a median: calculateMedian requires a non-empty array"
);
});

test("given a non-array, explains why", () => {
expect(describeMedian("banana")).toBe(
"Could not calculate a median: calculateMedian requires an array of numbers"
);
});

// Given an empty array
// When passed to describeMedian
Expand Down
11 changes: 11 additions & 0 deletions Sprint-1/implement/max.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
function findMax(elements) {
if (
!Array.isArray(elements) ||
elements.some((item) => typeof item !== "number")
) {
throw new Error("findMax requires an array of numbers");
}
let max = -Infinity;
for (const item of elements) {
if (item > max) max = item;
}
return max;
}

module.exports = findMax;
34 changes: 33 additions & 1 deletion Sprint-1/implement/max.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,39 @@ const findMax = require("./max.js");
// When passed to the max function
// Then it should return -Infinity
// Delete this test.todo and replace it with a test.
test.todo("given an empty array, returns -Infinity");
test("given an empty array, returns -Infinity", () => {
expect(findMax([])).toBe(-Infinity);
});

test("given one number, returns it", () => {
expect(findMax([7])).toBe(7);
});

test("given positive and negative numbers, returns the largest", () => {
expect(findMax([30, -50, 10, 40])).toBe(40);
});

test("given only negative numbers, returns the closest to zero", () => {
expect(findMax([-10, -3, -20])).toBe(-3);
});

test("given decimals, returns the largest", () => {
expect(findMax([1.5, 2.25, 2.2])).toBe(2.25);
});

test("throws if an element isn't a number", () => {
expect(() => findMax(["hey", 10, "hi", 60, 10])).toThrow(
new Error("findMax requires an array of numbers")
);
});

test("throws if not an array", () => {
for (const bad of ["hey", 42, undefined, null, {}]) {
expect(() => findMax(bad)).toThrow(
new Error("findMax requires an array of numbers")
);
}
});

// Given an array with one number
// When passed to the max function
Expand Down
14 changes: 13 additions & 1 deletion Sprint-1/implement/mean.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
function calculateMean(list) {}
function calculateMean(list) {
if (!Array.isArray(list) || list.some((item) => typeof item !== "number")) {
throw new Error("calculateMean requires an array of numbers");
}
if (list.length === 0) {
throw new Error("calculateMean requires a non-empty array");
}
let total = 0;
for (const item of list) {
total += item;
}
return total / list.length;
}

module.exports = calculateMean;
33 changes: 32 additions & 1 deletion Sprint-1/implement/mean.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,38 @@ const calculateMean = require("./mean.js");
// 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");
test("given [1, 2, 6], returns 3", () => {
expect(calculateMean([1, 2, 6])).toBe(3);
});

test("given a single number, returns it", () => {
expect(calculateMean([4])).toBe(4);
});

test("handles negative and decimal numbers", () => {
expect(calculateMean([-2, 2, -4, 4])).toBe(0);
expect(calculateMean([1.5, 2.5])).toBe(2);
});

test("throws for an empty array", () => {
expect(() => calculateMean([])).toThrow(
new Error("calculateMean requires a non-empty array")
);
});

test("throws for non-arrays and no argument", () => {
for (const bad of ["banana", 42, null, {}, undefined]) {
expect(() => calculateMean(bad)).toThrow(
new Error("calculateMean requires an array of numbers")
);
}
});

test("throws for arrays with non-numbers", () => {
expect(() => calculateMean([1, "2", 3])).toThrow(
new Error("calculateMean requires an array of numbers")
);
});

// Given an array with a single number
// When passed to calculateMean
Expand Down
11 changes: 11 additions & 0 deletions Sprint-1/implement/sum.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
function sum(elements) {
if (
!Array.isArray(elements) ||
elements.some((item) => typeof item !== "number")
) {
throw new Error("sum requires an array of numbers");
}
let total = 0;
for (const item of elements) {
total += item;
}
return total;
}

module.exports = sum;
28 changes: 27 additions & 1 deletion Sprint-1/implement/sum.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,33 @@ const sum = require("./sum.js");
// Given an empty array
// When passed to the sum function
// Then it should return 0
test.todo("given an empty array, returns 0")
test("given an empty array, returns 0", () => {
expect(sum([])).toBe(0);
});

test("given one number, returns it", () => {
expect(sum([5])).toBe(5);
});

test("given negative numbers, returns the correct total", () => {
expect(sum([10, -30, 5])).toBe(-15);
});

test("given decimals, returns the correct total", () => {
expect(sum([0.5, 0.25, 1])).toBe(1.75);
});

test("throws if an element isn't a number", () => {
expect(() => sum(["hey", 10, "hi", 60, 10])).toThrow(
new Error("sum requires an array of numbers")
);
});

test("throws if not an array", () => {
for (const bad of ["hey", 42, undefined, null, {}]) {
expect(() => sum(bad)).toThrow(new Error("sum requires an array of numbers"));
}
});

// Given an array with just one number
// When passed to the sum function
Expand Down
3 changes: 1 addition & 2 deletions Sprint-1/refactor/includes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Refactor the implementation of includes to use a for...of loop

function includes(list, target) {
for (let index = 0; index < list.length; index++) {
const element = list[index];
for (const element of list) {
if (element === target) {
return true;
}
Expand Down
28 changes: 28 additions & 0 deletions Sprint-1/stretch/aoc-2018-day1/solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const fs = require("fs");
const path = require("path");

const changes = fs
.readFileSync(path.join(__dirname, "input.txt"), "utf8")
.split(/\r?\n/)
.filter((line) => line.trim() !== "")
.map(Number);

// Part 1: resulting frequency after all changes
const finalFrequency = changes.reduce((total, change) => total + change, 0);
console.log("Part 1:", finalFrequency);

// Part 2: first frequency reached twice
let frequency = 0;
const seen = new Set([0]);
let firstRepeat;
while (firstRepeat === undefined) {
for (const change of changes) {
frequency += change;
if (seen.has(frequency)) {
firstRepeat = frequency;
break;
}
seen.add(frequency);
}
}
console.log("Part 2:", firstRepeat);
Loading