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

JavaScript 배열에서 중복 객체를 손쉽게 제거하는 방법

문제 상황

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]처럼 얕은 복사본을 만들어 처리하는 것이 좋습니다.