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
30 changes: 27 additions & 3 deletions Sprint-1/fix/median.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,33 @@
// or 'list' has mixed values (the function is expected to sort only numbers).

function calculateMedian(list) {
const middleIndex = Math.floor(list.length / 2);
const median = list.splice(middleIndex, 1)[0];
return median;
// if list is not an array return null.
if (!Array.isArray(list)) {
return null;
}

// filter the list to include only valid numbers (excludes Infinity, -Infinity, and NaN)
const numbers = list.filter(
(item) => typeof item === "number" && Number.isFinite(item)
);

// if numbers array is empty return null.
if (numbers.length === 0) {
return null;
}

// sort the numbers in the number array in ascending order.
numbers.sort((a, b) => a - b);

// find the middle index and store it in a variable.
const middleIndex = Math.floor(numbers.length / 2);

// if its an even array there are two middle indexes, so add them together and divide by two.
if (numbers.length % 2 === 0) {
return (numbers[middleIndex] + numbers[middleIndex - 1]) / 2;
}
// for odd arrays return middle index.
return numbers[middleIndex];
}

module.exports = calculateMedian;
22 changes: 17 additions & 5 deletions Sprint-1/fix/median.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ describe("calculateMedian", () => {
{ 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))
it(`returns the median for [${input}]`, () =>
expect(calculateMedian(input)).toEqual(expected))
);

[
Expand All @@ -24,7 +25,8 @@ describe("calculateMedian", () => {
{ 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 correct median for unsorted array [${input}]`, () =>
expect(calculateMedian(input)).toEqual(expected))
);

it("doesn't modify the input array [3, 1, 2]", () => {
Expand All @@ -33,8 +35,17 @@ describe("calculateMedian", () => {
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))
[
"not an array",
123,
null,
undefined,
{},
[],
["apple", null, undefined],
].forEach((val) =>
it(`returns null for non-numeric array (${val})`, () =>
expect(calculateMedian(val)).toBe(null))
);

[
Expand All @@ -45,6 +56,7 @@ describe("calculateMedian", () => {
{ 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))
it(`filters out non-numeric values and calculates the median for [${input}]`, () =>
expect(calculateMedian(input)).toEqual(expected))
);
});
13 changes: 12 additions & 1 deletion Sprint-1/implement/dedupe.js
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
function dedupe() {}
function dedupe(elements) {
const result = [];
for (let i = 0; i < elements.length; i++) {
if (!result.includes(elements[i])) {
result.push(elements[i]);
}
}

return result;
}

module.exports = dedupe;
25 changes: 22 additions & 3 deletions Sprint-1/implement/dedupe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,31 @@ E.g. dedupe([1, 2, 1]) target output: [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([]);
});

// Given an array with no duplicates
// When passed to the dedupe function
// Then it should return a copy of the original array
test("given an array with no duplicates, it should return a copy of the original array", () => {
const input = ["a", "b", "c"];
const result = dedupe(input);

// Given an array with strings or numbers
expect(result).toHaveLength(input.length);
expect(result).toEqual(input);
expect(result).not.toBe(input);
Comment on lines +27 to +32
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a chance that, even though result has incorrect elements (for example, []),
the two tests could still pass. Can you figure out why, and then fix the tests accordingly?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added .toHaveLength to ensure the returned array has the same number of elements as the original.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better but it is still not 100% bullet proof. What if result is ["a", "b", "x"]?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the test to ensure expected has the expected elements?
And optionally add another test to ensure input remains unchanged after the function call.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my research .toEqual already ensures the returned array has the exact expected elements. I also added an additional test to verify that calling the function does not change the original array.

});

// Given an array with strings
// When passed to the dedupe function
// Then it should remove the duplicate values, preserving the first occurence of each element
// Then it should remove duplicates and not modify the original array
test("given an array with strings, it should remove duplicates and preserve the original array", () => {
const input = ["a", "a", "a", "b", "b", "c"];
const original = [...input];

const result = dedupe(input);

expect(result).toEqual(["a", "b", "c"]);
expect(input).toEqual(original);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could combine this with the previous test.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now, thanks

});
18 changes: 17 additions & 1 deletion Sprint-1/implement/max.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
function findMax(elements) {
}
const numbersOnly = elements.filter(
(e) => typeof e === "number" && Number.isFinite(e)
);

if (numbersOnly.length === 0) {
return -Infinity;
}

let max = numbersOnly[0];

for (let i = 1; i < numbersOnly.length; i++) {
if (numbersOnly[i] > max) {
max = numbersOnly[i];
}
}

return max;
}
module.exports = findMax;
42 changes: 41 additions & 1 deletion Sprint-1/implement/max.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,68 @@ 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);
});

// Given an array with one number
// When passed to the max function
// Then it should return that number

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

// Given an array with both positive and negative numbers
// When passed to the max function
// Then it should return the largest number overall

test("given positive and negative numbers, returns the largest number", () => {
expect(findMax([-3, 7, -2, 5])).toBe(7);
});

// Given an array with just negative numbers
// When passed to the max function
// Then it should return the closest one to zero

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

// Given an array with decimal numbers
// When passed to the max function
// Then it should return the largest decimal number

test("given an array with decimal numbers, returns the clargest decimal number", () => {
expect(findMax([2.7, 6.9, 10.1])).toBe(10.1);
});

// Given an array with non-number values
// When passed to the max function
// Then it should return the max and ignore non-numeric values

test("given an array with non-number values, returns the max and ignore non-numeric values", () => {
expect(findMax([3, "dogs", 1, "cat", null])).toBe(3);
});

// Given an array with only non-number values
// When passed to the max function
// Then it should return the least surprising value given how it behaves for all other inputs

test("given an array with only non-number values, returns -Infinity", () => {
expect(findMax(["a", null, true, undefined])).toBe(-Infinity);
});

// Given an array with Nan
// When passed to the max function
// Then it should return the correct maximum value
test("given an array including Nan return correct maximum value", () => {
expect(findMax([11, NaN, 5])).toBe(11);
});

// Given an array with numeric string value
// When passed to the max function
// Then it should ignore the numeric string and return correct maximum value
test("given an array with numeric string value, it should ignore the numeric string and return correct maximum value", () => {
expect(findMax([8, "14", 2])).toBe(8);
});
8 changes: 8 additions & 0 deletions Sprint-1/implement/sum.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
function sum(elements) {
let total = 0;

for (let i = 0; i < elements.length; i++) {
if (typeof elements[i] === "number" && Number.isFinite(elements[i])) {
total += elements[i];
}
}
return total;
}

module.exports = sum;
31 changes: 30 additions & 1 deletion Sprint-1/implement/sum.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,53 @@ 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);
});

// Given an array with just one number
// When passed to the sum function
// Then it should return that number

test("given an array with one number, returns that number", () => {
expect(sum([42])).toBe(42);
});

// Given an array containing negative numbers
// When passed to the sum function
// Then it should still return the correct total sum

test("given an array containing negative numbers", () => {
expect(sum([-5, -6, -1])).toBe(-12);
});

// Given an array with decimal/float numbers
// When passed to the sum function
// Then it should return the correct total sum

test("given an array with decimal/float numbers, returns the correct total sum", () => {
expect(sum([2.75, -0.3, 0.0002])).toBeCloseTo(2.4502);
});

// Given an array containing non-number values
// When passed to the sum function
// Then it should ignore the non-numerical values and return the sum of the numerical elements

test("given an array containing non-number values, ignore the non-numerical values and return the sum of the numerical elements", () => {
expect(sum(["hello", 6, true, 14])).toBe(20);
});

// Given an array with only non-number values
// When passed to the sum function
// Then it should return the least surprising value given how it behaves for all other inputs

test("given an array with only non-number values, returns 0", () => {
expect(sum(["hello", undefined, "today", true])).toBe(0);
});

// Given an array including NaN
// When passed to the sum function
// Then it should ignore the NaN value
test("given an array that include NaN returns correct answer", () => {
expect(sum([7, 14, NaN])).toBe(21);
});
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