문제 상황
JavaScript를 사용하다 보면 객체 배열 안에 완전히 동일한 내용의 객체가 중복으로 들어 있는 경우를 자주 만나게 됩니다. 예를 들어 다음과 같은 배열이 있다고 가정해 보겠습니다.
const arr = [
{"title": "Assistant"},
{"month": "July"},
{"event": "Holiday"},
{"title": "Assistant"}
];위 배열에는 {"title": "Assistant"} 객체가 두 번 등장합니다. 우리가 작성해야 할 함수는 이러한 배열을 인자로 받아, 원본 배열의 모든 객체를 유지하면서 중복된 객체만 제거한 새로운 결과를 반환해야 합니다.
해결 방법
객체는 참조 타입이기 때문에 단순 비교 연산자(===)로는 값이 같은지 판단할 수 없습니다. 따라서 각 객체를 JSON.stringify()로 문자열로 변환한 뒤, 해시 맵 역할을 하는 객체에 해당 문자열이 이미 존재하는지 확인하는 방식으로 중복을 판별할 수 있습니다.
예제 코드
const arr = [
{"title": "Assistant"},
{"month": "July"},
{"event": "Holiday"},
{"title": "Assistant"}
];
const removeDuplicate = arr => {
const map = {};
for(let i = 0; i < arr.length; ){
const str = JSON.stringify(arr[i]);
if(map.hasOwnProperty(str)){
arr.splice(i, 1);
continue;
};
map[str] = true;
i++;
};
};
removeDuplicate(arr);
console.log(arr);실행 결과
코드를 실행하면 콘솔에 다음과 같이 중복이 제거된 배열이 출력됩니다.
[ { title: 'Assistant' }, { month: 'July' }, { event: 'Holiday' } ]코드 동작 원리
이 코드의 핵심 로직은 다음과 같습니다.
1. 직접 인덱스 제어: for 루프에서 증감식(i++)을 생략하고, 조건 분기 안에서 인덱스를 직접 관리합니다. 중복을 발견해 splice()로 요소를 삭제하면 뒤의 요소들이 앞으로 당겨지기 때문에, 이때는 인덱스를 증가시키지 않고 continue로 넘어갑니다.
2. 문자열 기반 중복 판별: 각 객체를 JSON.stringify()로 직렬화하여 고유한 문자열 키를 만들고, map 객체에 hasOwnProperty()로 해당 키의 존재 여부를 확인합니다. 처음 보는 객체라면 map에 기록한 후 인덱스를 증가시킵니다.
3. 제자리(in-place) 수정: 이 함수는 새 배열을 반환하는 대신 원본 배열을 직접 수정한다는 점에 유의하세요. 원본을 유지하고 싶다면 함수 시작 부분에서 [...arr]처럼 얕은 복사본을 만들어 처리하는 것이 좋습니다.