웹 개발을 하다 보면 URL 정보와 고유 ID를 담은 객체 배열에서 중복 데이터를 정리해야 하는 경우가 자주 발생합니다. 다음과 같은 객체 배열이 있다고 가정해 보겠습니다.
const arr = [
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello-how-are-you',
id: "23"
},
{
url: 'www.example.com/i-like-cats',
id: "24"
},
{
url: 'www.example.com/i-like-pie',
id: "25"
}
];위 배열에는 id가 "22"인 객체가 두 번 등장합니다. 우리가 작성할 JavaScript 함수는 이런 객체 배열을 인자로 받아 중복된 id 키를 가진 객체를 배열에서 제거하는 역할을 해야 하며, underscore 같은 외부 라이브러리 없이 순수 JavaScript만으로 구현해야 합니다.
구현 아이디어
핵심은 간단합니다. 이미 등장한 id를 기록할 객체(맵)를 하나 만들고, 배열을 순회하면서 해당 id가 맵에 이미 존재하면 그 요소를 삭제하고, 존재하지 않으면 맵에 기록한 뒤 다음 요소로 넘어가면 됩니다.
주목할 점은 splice()로 요소를 제거하면 배열 길이가 줄어들기 때문에, 제거 시에는 인덱스 i를 증가시키지 않고 그대로 유지해야 한다는 것입니다. 그래야 제거 직후 다음 요소를 놓치지 않고 검사할 수 있습니다.
코드 예제
const arr = [
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello',
id: "22"
},
{
url: 'www.example.com/hello-how-are-you',
id: "23"
},
{
url: 'www.example.com/i-like-cats',
id: "24"
},
{
url: 'www.example.com/i-like-pie',
id: "25"
}
];
const removeDuplicate = (arr = []) => {
const map = {};
for(let i = 0; i < arr.length; ){
const { id } = arr[i];
if(map.hasOwnProperty(id)){
arr.splice(i, 1);
}else{
map[id] = true;
i++;
};
};
};
removeDuplicate(arr);
console.log(arr);출력 결과
코드를 실행하면 콘솔에 다음과 같이 출력됩니다. 중복되었던 id "22" 객체가 하나로 정리된 것을 확인할 수 있습니다.
[
{ url: 'www.example.com/hello', id: '22' },
{ url: 'www.example.com/hello-how-are-you', id: '23' },
{ url: 'www.example.com/i-like-cats', id: '24' },
{ url: 'www.example.com/i-like-pie', id: '25' }
]참고: Set과 filter()를 활용한 더 간결한 방법
ES6의 Set과 filter()를 사용하면 원본 배열을 수정하지 않고도 동일한 결과를 얻을 수 있습니다.
const removeDuplicate = (arr) => {
const seen = new Set();
return arr.filter(item => {
if(seen.has(item.id)){
return false;
}
seen.add(item.id);
return true;
});
};
const uniqueArr = removeDuplicate(arr);filter() 방식은 기존 배열을 변경하지 않고 새 배열을 반환하므로 불변성(immutability)을 유지해야 하는 React, Redux 환경에서 특히 유용합니다. 반면 첫 번째 splice() 방식은 원본 배열 자체를 정리할 때 적합합니다. 상황에 맞게 선택해서 사용하세요.