이번 글에서는 여러 번 반복되는 요소가 섞여 있는 배열에서 단 한 번만 등장하는 요소만 골라 새로운 배열로 반환하는 JavaScript 함수를 작성하는 방법을 알아보겠습니다.
문제 이해하기
예를 들어 다음과 같은 숫자 배열이 있다고 가정해 봅시다.
const arr = [9, 5, 6, 8, 7, 7, 1, 1, 1, 1, 1, 9, 8];
이 배열에서 9, 7, 1, 8은 두 번 이상 등장하므로 제외되어야 하며, 기대하는 출력 결과는 다음과 같습니다.
const output = [5, 6];
풀이 접근 방식
핵심 아이디어는 간단합니다. 각 요소에 대해 다음 두 값을 비교합니다.
indexOf(value): 해당 값이 배열에서 처음 나타나는 인덱스lastIndexOf(value): 해당 값이 배열에서 마지막으로 나타나는 인덱스
두 인덱스가 서로 같다면 그 요소는 배열 전체에서 단 한 번만 등장한 것이므로 결과 배열에 추가하면 됩니다. 다르다면 중복된 요소이므로 건너뜁니다.
예제 코드
const arr = [9, 5, 6, 8, 7, 7, 1, 1, 1, 1, 1, 9, 8];
const findDistinct = arr => {
const res = [];
for(let i = 0; i < arr.length; i++){
if(arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i])){
continue;
};
res.push(arr[i]);
};
return res;
};
console.log(findDistinct(arr));
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[5, 6]
추가 팁: filter()로 더 간결하게 작성하기
filter() 메서드를 사용하면 동일한 로직을 더 짧고 선언적인 스타일로 표현할 수 있습니다.
const findDistinct = arr => arr.filter((val, _, self) => self.indexOf(val) === self.lastIndexOf(val)); console.log(findDistinct(arr)); // [5, 6]
다만 위의 두 방법 모두 요소마다 배열을 다시 탐색하기 때문에 시간 복잡도는 O(n²)입니다. 배열의 크기가 매우 크다면 Map 객체를 사용해 각 값의 등장 횟수를 한 번의 순회(O(n))로 미리 계산한 뒤, 개수가 1인 요소만 필터링하는 방식이 더 효율적입니다.