Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript로 여러 배열의 요소를 번갈아 가며 하나로 합치는 방법

문제 상황

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 ]

코드 동작 원리

  1. pickElements 함수는 나머지 매개변수 ...arrs를 통해 전달된 모든 배열을 수집합니다.
  2. arrs.map(el => el.length)로 각 배열의 길이를 추출한 뒤, Math.max()로 그중 가장 큰 값을 구해 max에 저장합니다.
  3. 바깥 for문이 인덱스 i를 0부터 max - 1까지 순회하고, 안쪽 for문이 각 배열 arrs[j]를 차례로 확인합니다.
  4. 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 같은 값도 정상적으로 결과 배열에 포함됩니다.