문제 상황
다음과 같이 배열 안에 배열이 중첩된 2차원 배열이 주어져 있다고 가정해 보겠습니다.
const arr = [[12, 56], [3, 45], [23, 2], [2, 6], [2, 8]];
바깥 배열의 길이에는 제한이 없지만, 각 하위 배열에는 반드시 두 개의 숫자만 포함되어야 한다는 점에 유의해야 합니다.
하위 배열의 두 숫자는 하나의 분수를 나타냅니다. 예를 들어 첫 번째 하위 배열 [12, 56]은 분수 12/56을, 두 번째 하위 배열 [3, 45]는 분수 3/45를 의미하는 식입니다.
요구 사항
우리가 작성해야 하는 자바스크립트 함수는 다음 조건을 충족해야 합니다.
- 이처럼 구성된 배열을 인수로 받습니다.
- 모든 하위 배열이 나타내는 분수들의 합을 계산합니다.
- 값을 소수로 변환하지 않고 분수 형태 그대로 연산합니다.
- 최종 결과 분수를 나타내는 두 개의 요소(분자, 분모)를 가진 배열을 반환합니다.
예제 코드
다음은 위 문제를 해결하는 전체 코드입니다.
const arr = [[12, 56], [3, 45], [23, 2], [2, 6], [2, 8]];
const gcd = (a, b) => {
let num = 2, res = 1;
while(num <= Math.min(a, b)){
if(a % num === 0 && b % num === 0){
res = num;
};
num++;
};
return res;
}
const sumFrac = (a, b) => {
const aDenom = a[1], aNumer = a[0];
const bDenom = b[1], bNumer = b[0];
let resDenom = aDenom * bDenom;
let resNumer = (aDenom*bNumer) + (bDenom*aNumer);
const greatestDivisor = gcd(resDenom, resNumer);
return [resNumer/greatestDivisor, resDenom/greatestDivisor];
};
const sumArrayOfFractions = arr => {
return arr.reduce((acc, val) => sumFrac(acc, val));
};
코드 동작 원리
코드가 어떤 순서로 동작하는지 단계별로 살펴보겠습니다.
- gcd 함수: 두 수의 최대공약수(GCD)를 구합니다. 2부터 두 수 중 작은 값까지 차례대로 나누어 보면서, 두 수를 모두 나누어 떨어지게 하는 가장 큰 수를 찾아 반환합니다.
- sumFrac 함수: 두 개의 분수를 더하는 핵심 로직입니다. 분모끼리 곱해 공통 분모를 만들고, 교차 곱셈 방식으로 분자를 계산한 뒤 최대공약수로 약분하여 기약 분수 형태의 배열을 반환합니다.
- sumArrayOfFractions 함수: 배열 내장 메서드
reduce()를 활용해 첫 번째 분수부터 마지막 분수까지 누적하여 더해 나갑니다. 초기값 없이 호출했기 때문에 첫 번째 하위 배열이 시작값으로 사용됩니다.
참고로 위의 gcd 함수는 반복적으로 나누어 확인하는 방식이라 직관적이지만, 숫자가 커지면 성능이 떨어질 수 있습니다. 유클리드 호제법을 사용하면 다음과 같이 더 효율적으로 구현할 수 있습니다.
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
출력 결과
콘솔에 다음과 같은 결과가 출력됩니다.
[ 1731, 140 ]
즉, 주어진 다섯 개의 분수 12/56, 3/45, 23/2, 2/6, 2/8을 모두 더하면 1731/140이 되며, 이 값은 이미 약분된 기약 분수 형태로 반환됩니다.