프로그래밍을 하다 보면 숫자 배열에서 특정 조건을 만족하는 요소들을 추출해야 하는 경우가 자주 있습니다. 이번 글에서는 배열 전체 합계를 기준으로, 주어진 퍼센트 이하가 될 때까지 앞쪽 요소들을 순서대로 모으는 함수를 JavaScript로 구현해 보겠습니다.
문제 정의
다음과 같은 숫자 리터럴 배열이 있다고 가정해 봅시다.
const numbers = [10, 6200, 20, 20, 350, 900, 26, 78, 888, 10000, 78, 15000, 200, 1280, 2000, 450];
우리가 작성할 함수는 두 개의 인자를 받습니다. 첫 번째는 숫자 배열이고, 두 번째는 0부터 100 사이의 값으로 특정 백분율(%)을 나타냅니다. 편의상 이 값을 x라고 부르겠습니다.
함수는 원본 배열의 처음 n개 요소 중에서, 그 합이 전체 합계의 x%보다 작거나 같은 부분 배열을 반환해야 합니다. 즉, 요소를 하나씩 더해가다가 기준치를 초과하는 순간 멈추고, 그때까지 모은 요소들만 반환하는 것입니다.
간단한 예시
const numbers = [12, 10, 6, 8, 4, 2, 8];
이 배열의 전체 합계는 50입니다. 두 번째 인자로 25를 넘겨주면(x = 25), 전체 합계인 50의 25%, 즉 12.5와 같거나 그보다 작아질 때까지의 첫 n개 요소를 반환해야 합니다.
첫 번째 요소 12는 기준값 12.5 이하이므로 포함되지만, 여기에 두 번째 요소 10을 더하면 22가 되어 기준값을 초과합니다. 따라서 이 경우에는 첫 번째 요소 하나만 담긴 배열이 반환됩니다.
구현 코드
구현 방식은 간단합니다. 먼저 reduce() 메서드로 배열의 전체 합계를 구하고, for 반복문 안에서 요소를 하나씩 누적하면서 조건에 맞는 새로운 배열을 만들어 줍니다.
const numbers = [10, 6200, 20, 20, 350, 900, 26, 78, 888, 10000, 78, 15000, 200, 1280, 2000, 450];
const findPercent = (arr, percent) => {
const sum = arr.reduce((acc, val) => acc + val);
const part = [];
let curr = 0;
for (let i = 0; i < arr.length; i++) {
curr += arr[i];
if (curr <= (sum * percent) / 100) {
part.push(arr[i]);
} else {
break;
}
}
return part;
};
console.log(findPercent(numbers, 35));
console.log(findPercent(numbers, 5));
console.log(findPercent(numbers, 65));
console.log(findPercent(numbers, 95));
실행 결과
콘솔 출력 결과는 다음과 같습니다.
[
10, 6200, 20, 20,
350, 900, 26, 78,
888
]
[ 10 ]
[
10, 6200, 20,
20, 350, 900,
26, 78, 888,
10000, 78
]
[
10, 6200, 20, 20,
350, 900, 26, 78,
888, 10000, 78, 15000,
200, 1280
]
코드 동작 원리
동작 과정을 단계별로 살펴보면 다음과 같습니다.
- 전체 합계 계산:
reduce()메서드를 사용해 배열의 모든 요소를 더한 총합을 구합니다. - 누적 합 비교: 반복문을 돌며 각 요소를
curr변수에 누적하고, 이 값이 전체 합계의 percent% 이하인지 확인합니다. - 조건 충족 시 추가: 조건을 만족하면 해당 요소를 결과 배열
part에 push합니다. - 조건 초과 시 종료: 기준값을 초과하는 순간
break로 반복문을 빠져나오고, 지금까지 모은 배열을 반환합니다.
이 방식은 배열을 한 번만 순회하면 되므로 시간 복잡도가 O(n)으로 매우 효율적입니다. 덕분에 데이터 양이 많아져도 성능 저하 없이 안정적으로 동작합니다. 또한 로직이 단순하기 때문에 상위 n% 매출 집계, 누적 분포 분석 등 실무에서도 다양하게 응용할 수 있습니다.