문제 소개
다음과 같이 서로 겹치는 값을 가진 두 개의 배열이 있다고 가정해 보겠습니다.
const arr1 = [2, 4, 5, 3, 7, 8, 9]; const arr2 = [1, 4, 5, 2, 3, 7, 6];
이 두 배열을 입력받아 하나로 합치되, 동일한 값이 여러 번 등장하지 않도록 중복을 제거한 새로운 배열을 반환하는 JavaScript 함수를 작성해야 합니다. 즉, 각 요소는 결과 배열에 정확히 한 번만 나타나야 합니다.
includes()를 활용한 구현
가장 기본적인 접근 방식은 결과 배열에 해당 값이 이미 존재하는지 includes() 메서드로 확인한 뒤, 존재하지 않는 경우에만 추가하는 것입니다.
const arr1 = [2, 4, 5, 3, 7, 8, 9];
const arr2 = [1, 4, 5, 2, 3, 7, 6];
const mergeArrays = (first, second) => {
const { length: l1 } = first;
const { length: l2 } = second;
const res = [];
let temp = 0;
// 전체 길이(l1 + l2)만큼 반복하며
// 앞부분에서는 두 번째 배열을, 뒷부분에서는 첫 번째 배열을 검사합니다.
for(let i = 0; i < l1 + l2; i++){
if(i >= l1){
temp = i - l1;
if(!res.includes(first[temp])){
res.push(first[temp]);
}
}else{
temp = i;
if(!res.includes(second[temp])){
res.push(second[temp]);
}
}
}
return res;
};
console.log(mergeArrays(arr1, arr2));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다. 두 배열의 모든 고유한 값이 포함되며, 양쪽에 공통으로 존재하는 값(2, 3, 4, 5, 7)은 한 번만 나타납니다.
[ 1, 4, 5, 2, 3, 7, 6, 8, 9 ]
Set을 활용한 더 간결한 방법
ES6에서 도입된 Set 객체는 중복 값을 허용하지 않는 자료구조입니다. 이를 활용하면 위의 반복문 로직을 단 한 줄로 대체할 수 있습니다.
const mergeArrays = (first, second) => [...new Set([...first, ...second])]; console.log(mergeArrays([2, 4, 5, 3, 7, 8, 9], [1, 4, 5, 2, 3, 7, 6])); // [2, 4, 5, 3, 7, 8, 9, 1, 6]
두 방식의 차이점은 다음과 같습니다.
- 요소 순서:
Set방식은 첫 번째 배열의 원소가 먼저 배치되므로, 반복문 방식과 요소 순서가 다를 수 있습니다. 순서가 중요하다면 이 점을 유의해야 합니다. - 성능:
includes()는 매번 처음부터 선형 탐색을 수행하므로 전체 시간 복잡도가 O(n²)에 가깝습니다. 반면Set은 해시 기반으로 동작하여 평균 O(n)으로 처리되므로, 배열 크기가 클수록 훨씬 유리합니다.
따라서 특별한 이유가 없다면 실무에서는 Set을 활용한 방식을 사용하는 것이 코드 가독성과 성능 면에서 모두 권장됩니다.