문제 상황
JavaScript에서 임의 개수의 배열을 입력받아, 모든 배열의 요소를 번갈아 가며(교차로) 선택해 새로운 배열을 만드는 함수를 작성해야 합니다.
예를 들어, 아래와 같은 세 개의 배열이 함수에 입력된다고 가정해 보겠습니다.
입력
const arr1 = [1, 2, 3, 4];
const arr2 = [11, 12, 13, 14];
const arr3 = ['a', 'b', 'c'];
각 배열에서 첫 번째 요소부터 순서대로 하나씩 교차로 가져오므로, 기대하는 출력 결과는 다음과 같습니다.
출력
const output = [1, 11, 'a', 2, 12, 'b', 3, 13, 'c', 4, 14];
여기서 주목할 점은 세 배열의 길이가 서로 다르다는 것입니다. 가장 짧은 배열인 arr3의 요소가 모두 소진되면, 남은 두 배열의 요소만 이어서 결과에 포함됩니다.
해결 방법
이 문제는 다음과 같은 단계로 접근할 수 있습니다.
- 나머지 매개변수(Rest Parameter): 함수 선언 시
...arrs형태를 사용하면, 호출 시 전달되는 배열의 개수에 제한 없이 모든 배열을 하나의 배열로 묶어 받을 수 있습니다. - 최대 길이 계산:
Math.max()와map()을 조합해 입력된 배열 중 가장 긴 배열의 길이를 구합니다. 이 값이 외부 반복문의 기준이 됩니다. - 교차 순회: 바깥 반복문은 인덱스를, 안쪽 반복문은 배열을 순회하며 해당 위치에 요소가 존재할 때만 결과 배열에 추가합니다.
구현 코드
위 로직을 적용한 전체 코드는 다음과 같습니다.
const arr1 = [1, 2, 3, 4];
const arr2 = [11, 12, 13, 14];
const arr3 = ['a', 'b', 'c'];
const pickElements = (...arrs) => {
const res = [];
const max = Math.max(...arrs.map(el => el.length));
for(let i = 0; i < max; i++){
for (let j = 0; j < arrs.length; j++){
if(arrs[j][i]){
res.push(arrs[j][i]);
}
};
};
return res;
};
console.log(pickElements(arr1, arr2, arr3));
실행 결과
[ 1, 11, 'a', 2, 12, 'b', 3, 13, 'c', 4, 14 ]
코드 동작 원리
pickElements함수는 나머지 매개변수...arrs를 통해 전달된 모든 배열을 수집합니다.arrs.map(el => el.length)로 각 배열의 길이를 추출한 뒤,Math.max()로 그중 가장 큰 값을 구해max에 저장합니다.- 바깥
for문이 인덱스i를 0부터max - 1까지 순회하고, 안쪽for문이 각 배열arrs[j]를 차례로 확인합니다. if(arrs[j][i])조건을 통해 해당 인덱스에 요소가 존재하는 경우에만res배열에 push하므로, 길이가 짧은 배열은 자연스럽게 건너뛰어집니다.
참고: falsy 값 처리 주의점
위 코드의 if(arrs[j][i]) 조건은 값의 존재 여부를 truthy/falsy로 판단하기 때문에, 배열에 0, false, 빈 문자열('') 같은 falsy 값이 포함되어 있으면 해당 요소가 누락될 수 있습니다.
모든 유효한 요소를 확실히 포함하려면 아래처럼 in 연산자나 typeof 검사를 활용하는 것이 안전합니다.
if(i in arrs[j]){
res.push(arrs[j][i]);
}이렇게 수정하면 0이나 false 같은 값도 정상적으로 결과 배열에 포함됩니다.