JavaScript 개발 중에는 하나의 배열을 받아서, 원본 배열의 요소들을 정확히 길이가 2인 하위 배열(청크)로 묶어 새로운 배열을 반환해야 하는 경우가 자주 있습니다.
이때 원본 배열의 길이가 2로 나누어 떨어지지 않는다면, 마지막 하위 배열에는 요소가 하나만 남겨져야 합니다.
문제 이해하기
예를 들어, 입력 배열이 다음과 같다고 가정해 보겠습니다.
const arr = [1, 2, 3, 4, 5, 6, 7];
그렇다면 기대하는 출력 결과는 다음과 같습니다.
const output = [[1, 2], [3, 4], [5, 6], [7]]
구현 코드
다음은 위 문제를 해결하는 전체 코드입니다.
const arr = [1, 2, 3, 4, 5, 6, 7];
const chunk = arr => {
const size = 2;
const chunkedArray = [];
for (let i = 0; i < arr.length; i++) {
const last = chunkedArray[chunkedArray.length - 1];
if(!last || last.length === size){
chunkedArray.push([arr[i]]);
}else{
last.push(arr[i]);
}
};
return chunkedArray;
};
console.log(chunk(arr));실행 결과
콘솔에 다음과 같은 출력이 표시됩니다.
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ] ]
코드 동작 원리
이 코드의 핵심 로직을 단계별로 살펴보면 다음과 같습니다.
- size 변수: 각 하위 배열의 최대 크기를 정의합니다. 여기서는 2로 설정했습니다.
- last 변수: 지금까지 만들어진 마지막 하위 배열을 참조합니다.
- 조건 검사: 마지막 하위 배열이 아직 없거나 이미 크기가 2에 도달했다면, 새로운 하위 배열을 만들고 현재 요소를 넣습니다.
- 요소 추가: 그 외의 경우에는 기존 마지막 하위 배열에 현재 요소를 이어서 추가합니다.
이 방식은 배열을 한 번만 순회하면서 결과를 만들기 때문에 시간 복잡도가 O(n)으로 효율적입니다.
대안: slice() 메서드 활용하기
코드를 더 간결하게 작성하고 싶다면 slice() 메서드를 활용할 수도 있습니다.
const chunk = (arr, size = 2) =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
);
console.log(chunk([1, 2, 3, 4, 5, 6, 7]));
// [[1, 2], [3, 4], [5, 6], [7]]이 방식은 필요한 청크의 개수를 Math.ceil()로 미리 계산한 뒤, 각 인덱스에 해당하는 구간을 잘라내어 새 배열을 구성합니다. 원본 배열을 변경하지 않으므로 부작용 없이 안전하게 사용할 수 있다는 장점이 있습니다.