다음과 같이 중복된 요소를 포함하고 있는 배열이 있다고 가정해 보겠습니다.
const arr = [1,1,2,2,3,4,4,5];
우리가 작성해야 할 JavaScript 함수는 이러한 배열을 입력받아 새로운 배열을 반환하는 것입니다. 여기서 주의할 점은 단순히 중복을 제거하는 것이 아니라, 원본 배열에서 딱 한 번만 등장하는 요소들만 골라 담아야 한다는 것입니다. 즉, 1, 2, 4처럼 두 번 이상 나타나는 값은 모두 제외되어야 합니다.
해결 아이디어
핵심은 indexOf()와 lastIndexOf() 메서드를 함께 활용하는 것입니다. 어떤 요소가 배열 안에서 유일하다면, 해당 요소가 처음 등장하는 인덱스와 마지막으로 등장하는 인덱스는 반드시 동일합니다. 따라서 두 값이 다르다면 그 요소는 두 번 이상 등장한 중복 요소이므로 결과에서 제외하면 됩니다.
예제 코드
const arr = [1,1,2,2,3,4,4,5];
const extractUnique = arr => {
const res = [];
for(let i = 0; i < arr.length; i++){
// 첫 등장 위치와 마지막 등장 위치가 다르면 중복 요소이므로 건너뜀
if(arr.lastIndexOf(arr[i]) !== arr.indexOf(arr[i])){
continue;
}
res.push(arr[i]);
}
return res;
};
console.log(extractUnique(arr));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[ 3, 5 ]
코드 설명
- indexOf(arr[i]) : 현재 요소가 배열에서 처음으로 등장하는 위치를 반환합니다.
- lastIndexOf(arr[i]) : 현재 요소가 배열에서 마지막으로 등장하는 위치를 반환합니다.
- 두 값이 같다는 것은 해당 요소가 배열 전체에서 단 한 번만 존재한다는 의미이므로, 결과 배열
res에 추가됩니다.
위 예제에서는 1, 2, 4가 각각 두 번씩 등장하기 때문에 제외되고, 오직 한 번만 등장한 3과 5만 최종 배열에 담기게 됩니다.
참고로 이 방식은 각 요소마다 indexOf와 lastIndexOf를 호출하므로 시간 복잡도가 O(n²)입니다. 배열의 크기가 매우 큰 경우에는 Map 객체를 사용해 각 요소의 등장 횟수를 미리 집계한 뒤 필터링하는 방식(O(n))을 고려하는 것이 더 효율적입니다.