1. 실패한 테스트 케이스 작성.
-> 아직 테스트 케이스에 맞는 파일을 생성하지 않았으므로 stats.max 함수가 존재하지 않으니 TypeError: stats.max is not a function 이런 오류 발생
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성
<stats.js>
exports.max = numbers => {
let result = numbers[0];
numbers.forEach(n => {
if (n > result) {
result = n;
}
});
return result;
};
3. 성공한 코드에서 리팩토링 진행
<stats.js>
exports.max = numbers => Math.max(...numbers);
1. 실패한 테스트 케이스 작성.
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
it('gets minimum value', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1);
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성 + 리팩토링 된 코드
<stats.js>
exports.max = numbers => Math.max(...numbers);
exports.min = numbers => Math.min(...numbers);
1. 실패한 테스트 케이스 작성.
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
it('gets minimum value', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1);
});
it('gets average value', () => {
expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성
<stats.js>
exports.max = numbers => Math.max(...numbers);
exports.min = numbers => Math.min(...numbers);
exports.avg = numbers => {
const sum = numbers.reduce((acc, current) => acc + current, 0);
return sum / numbers.length;
};
3. 성공한 코드에서 리팩토링 진행
<stats.js>
max, min 생략
exports.avg = numbers =>
numbers.reduce(
(acc, current, index, {array}) => acc + current / length,
0
);
잠깐)
1. reduce 함수 - 네개의 인자
- 누산기 (acc)
- 현재 값 (cur)
- 현재 인덱스 (idx)
- 원본 배열 (src)
2. 구조 분해 할당
- 구조 분해 문법을 통해 array.length에서 위와 같이 {array}를 통해 중복코드 제거.
numbers.reduce( (acc, current, index, array) => acc + current / array.length, 0 );
1. 실패한 테스트 케이스 작성.
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
it('gets minimum value', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1);
});
it('gets average value', () => {
expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
});
describe('median', () => {
it('sorts the array', () => {
expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
});
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성
<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);
1. 실패한 테스트 케이스 작성.
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
it('gets minimum value', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1);
});
it('gets average value', () => {
expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
});
describe('median', () => {
it('sorts the array', () => {
expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
});
it('gets the median for odd length', () => {
expect(stats.median([1, 2, 3, 4, 5])).toBe(3);
});
it('gets the median for even length', () => {
expect(stats.median([1, 2, 3, 4, 5, 6])).toBe(3.5);
});
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성
<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);
exports.median = numbers => {
const middle = Math.floor(numbers.length / 2);
if (numbers.length % 2) {
// 홀수
return numbers[middle];
}
return (numbers[middle - 1] + numbers[middle]) / 2;
};
3. 성공한 코드에서 리팩토링 진행
<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);
exports.median = numbers => {
const { length } = numbers;
const middle = Math.floor(length / 2);
return length % 2
? numbers[middle]
: (numbers[middle - 1] + numbers[middle]) / 2;
1번상황: 주어진 값들 중에서 가장 자주 나타난 값이 결과
[1,2,2,2,3] → 2
2번 상황: 모든 값들의 빈도가 똑같다면 최빈값은 없다
[1,2,3], [1,1,2,2,3,3] → null
3번 상황: 빈도가 똑같은 값이 여러개라면, 결과값도 여러개.
[1,2,2,3,3,4] → [2,3]
1. 실패한 테스트 케이스 작성.
<stats.test.js>
const stats = require('./stats');
describe('stats', () => {
it('gets maximum value', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
});
it('gets minimum value', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1);
});
it('gets average value', () => {
expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
});
describe('median', () => {
it('sorts the array', () => {
expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
});
it('gets the median for odd length', () => {
expect(stats.median([1, 2, 3, 4, 5])).toBe(3);
});
it('gets the median for even length', () => {
expect(stats.median([1, 2, 3, 4, 5, 6])).toBe(3.5);
});
});
describe('mode', () => {
//1번 상황
it('has one mode', () => {
expect(stats.mode([1, 2, 2, 2, 3])).toBe(2);
});
//2번 상황
it('has no mode', () => {
expect(stats.mode([1, 2, 3])).toBe(null);
});
//3번 상황
it('has multiple mode', () => {
expect(stats.mode([1, 2, 2, 3, 3, 4])).toEqual([2, 3]);
});
});
});
2. 실패한 테스트 케이스를 성공하기 위한 코드 작성
<stats.js>
max, min, avg, sort, median 생략
exports.mode = numbers => {
const counts = new Map();
numbers.forEach(n => {
const count = counts.get(n) || 0;
counts.set(n, count + 1);
});
//1번 상황
const maxCount = Math.max(...counts.values());
const modes = [...counts.keys()].filter(
number => counts.get(number) === maxCount
);
//2번 상황
if (modes.length === numbers.length) {
// 최빈값이 없음
return null;
}
//3번 상황
if (modes.length > 1) {
// 최빈값이 여러개
return modes;
}
// 최빈값이 하나
return modes[0];
};
3. 성공한 코드에서 리팩토링 진행
<stats.js>
max, min, avg, sort, median 생략
exports.mode = numbers => {
const counts = numbers.reduce(
(acc, current) => acc.set(current, acc.get(current) + 1 || 1),
new Map()
);
const maxCount = Math.max(...counts.values());
const modes = [...counts.keys()].filter(
number => counts.get(number) === maxCount
);
if (modes.length === numbers.length) {
// 최빈값이 없음
return null;
}
if (modes.length > 1) {
// 최빈값이 여러개
return modes;
}
// 최빈값이 하나
return modes[0];
};