Skip to content

Commit 77173a7

Browse files
feat: add variance algorithm
1 parent 5c39e87 commit 77173a7

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

‎Maths/Variance.js‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @function variance
3+
* @description Calculates the variance of an array of numbers.
4+
* Variance measures how far each number in the set is from the mean.
5+
* This calculates population variance.
6+
* @param {number[]} arr - An array of numbers
7+
* @returns {number} - The variance
8+
* @see https://en.wikipedia.org/wiki/Variance
9+
* @example variance([2, 4, 4, 4, 5, 5, 7, 9]) => 4
10+
* @example variance([1, 2, 3]) => 0.667
11+
*/
12+
const variance = (arr) => {
13+
if (!Array.isArray(arr) || arr.length === 0) {
14+
throw new TypeError('Input must be a non-empty array')
15+
}
16+
if (!arr.every((n) => typeof n === 'number' && !isNaN(n))) {
17+
throw new TypeError('All elements must be numbers')
18+
}
19+
const mean = arr.reduce((sum, n) => sum + n, 0) / arr.length
20+
return arr.reduce((sum, n) => sum + Math.pow(n - mean, 2), 0) / arr.length
21+
}
22+
23+
export { variance }

‎Maths/test/Variance.test.js‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { variance } from '../Variance.js'
2+
3+
describe('variance', () => {
4+
test('variance([2,4,4,4,5,5,7,9]) returns 4', () => {
5+
expect(variance([2, 4, 4, 4, 5, 5, 7, 9])).toBeCloseTo(4)
6+
})
7+
8+
test('variance([1,2,3]) returns ~0.667', () => {
9+
expect(variance([1, 2, 3])).toBeCloseTo(0.667, 2)
10+
})
11+
12+
test('variance of identical elements returns 0', () => {
13+
expect(variance([5, 5, 5, 5])).toBe(0)
14+
})
15+
16+
test('variance single element returns 0', () => {
17+
expect(variance([42])).toBe(0)
18+
})
19+
20+
test('variance works with negative numbers', () => {
21+
expect(variance([-2, -1, 0, 1, 2])).toBeCloseTo(2)
22+
})
23+
24+
test('variance([1,2,3,4,5]) returns 2', () => {
25+
expect(variance([1, 2, 3, 4, 5])).toBeCloseTo(2)
26+
})
27+
28+
test('variance does not mutate original array', () => {
29+
const arr = [1, 2, 3]
30+
variance(arr)
31+
expect(arr).toEqual([1, 2, 3])
32+
})
33+
34+
test('throws TypeError for empty array', () => {
35+
expect(() => variance([])).toThrow(TypeError)
36+
})
37+
38+
test('throws TypeError for non-array input', () => {
39+
expect(() => variance('123')).toThrow(TypeError)
40+
})
41+
42+
test('throws TypeError for array with non-numbers', () => {
43+
expect(() => variance([1, 'two', 3])).toThrow(TypeError)
44+
})
45+
})

0 commit comments

Comments
 (0)