javascript 배열 중복 제거: 실무 적용법과 주의점 총정리
javascript 배열 중복 제거에 관한 실무 가이드입니다. Set, filter, reduce 등 여러 방법의 구현과 성능·안전성 고려사항, 코드 예제와 체크리스트를 제공합니다.
javascript 배열 중복 제거이 필요한 상황
javascript 배열 중복 제거는 배열에 중복 값이 존재해 비즈니스 로직이나 렌더링, API 요청 전 데이터 정합성을 확보해야 할 때 자주 필요합니다. 이 글에서는 javascript 배열 중복 제거를 실무에서 바로 적용할 수 있도록 방법별 구현, 성능 비교, 보안·운영 주의점, 그리고 적용 시점과 피해야 할 경우를 정리합니다.
javascript 배열 중복 제거 핵심 개념
중복 제거는 크게 값 기반(원시값)과 참조 기반(객체)으로 나뉩니다. 원시값은 Set으로 간단히 처리 가능하지만, 객체는 비교 기준(key) 정의가 필요합니다. 시간 복잡도와 메모리 사용량을 고려해 적절한 알고리즘을 선택해야 합니다.
javascript 배열 중복 제거 실무 예제
아래 예제는 원시값(숫자/문자열)과 객체 배열에서 중복을 제거하는 방법을 보여줍니다.
// 원시값 - Set 사용 (간단, 빠름) const arr1 = [1,2,2,3,4,4,5]; const unique1 = [...new Set(arr1)]; console.log(unique1); // [1,2,3,4,5] // 원시값 - filter 사용 (indexOf 기반) const unique2 = arr1.filter((v, i, a) => a.indexOf(v) === i); // 객체 배열 - key 기준으로 중복 제거 const users = [ {id:1, name:'A'}, {id:2, name:'B'}, {id:1, name:'A2'} ]; const uniqueById = Array.from( users.reduce((map, user) => map.set(user.id, user), new Map()).values() ); // 또는 const seen = new Set(); const uniqueById2 = users.filter(u => { if (seen.has(u.id)) return false; seen.add(u.id); return true; }); // 정렬 기반 제거 (메모리 절약 목적) const arr2 = [3,1,2,3,2,1]; arr2.sort((a,b) => a-b); const uniqueSorted = arr2.filter((v,i,a) => i === 0 || a[i-1] !== v); console.log(uniqueById, uniqueById2, uniqueSorted);
Set 사용법과 장단점
Set은 원시값 처리에 가장 간단하고 읽기 쉬운 방법입니다. 구현이 간단하고 V8 등 엔진에서 최적화되어 있어 일반적으로 빠릅니다. 다만 객체 비교에는 적합하지 않으며, 순서가 중요한 경우 원본 순서 보장이 필요하다면 스프레드 방식이 아닌 filter 기반 보정이 필요합니다.
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | Set | filter(indexOf) | reduce/map+Set |
| 장점 | 간단, 빠름 | 원본 순서 보장 | 유연성, 커스텀 가능 |
| 단점 | 객체 비교 불가 | O(n^2) 위험(naive) | 구현 복잡도 증가 |
언제 쓰면 좋고 언제 피해야 할까
-
언제 쓰면 좋은가:
- 원시값 배열에서 빠르게 중복을 제거하고 싶을 때 (Set 권장)
- 객체 배열에서 특정 키(id, email)로 중복을 제거할 때
- UI 렌더링 전에 불필요한 중복 항목을 제거해 렌더 비용을 줄이고자 할 때
-
언제 피해야 하는가:
- 객체 전체 내용을 깊이 비교해야 하는 경우(깊은 비교로 인한 비용이 크므로 설계 재검토 필요)
- 입력 데이터의 순서가 엄격히 보존되어야 하고, Set 사용이 순서 변경을 일으킬 수 있는 상황
- 데이터가 매우 크고 메모리 제약이 있는 환경에서는 정렬 기반 스트리밍 처리 고려
실무 체크리스트
- 입력값 타입(원시/객체)을 확인했는가?
- 중복 판단 기준(key)이 명확한가? 예: id, email
- 순서 보존이 필요한가? 필요하면 filter/seen 사용
- 데이터 크기로 메모리 영향도를 계산했는가?
- 중복 제거 후 불변성(원본 보존)을 유지할지 결정했는가?
- 동시성/비동기 환경에서 race 조건이 없는가?
성능·보안·운영 주의점
- 성능:
- Set은 평균 O(n)으로 효율적이나 객체 비교엔 적합하지 않음.
- indexOf 기반 filter는 최악 O(n^2)이 될 수 있어 큰 배열엔 피해야 함.
- 정렬 기반 방법은 O(n log n)이지만 메모리 절감 또는 스트리밍에 유리할 수 있음.
- 보안:
- 외부 입력 데이터를 비교 키로 사용할 때(예: user-provided id) 조작 가능성 검토. 신뢰할 수 있는 키인지 확인 필요.
- 민감 정보(PII)를 비교 키로 사용하면 로그/캐시 등에 노출될 수 있으므로 주의.
- 운영:
- 대량 데이터 처리 파이프라인(백엔드/배치)에서는 메모리 사용량과 GC 영향을 모니터링할 것.
- 프론트엔드에서 브라우저 메모리 한계로 인해 대형 배열을 처리할 경우 페이징 또는 서버 사이드에서 처리 권장.
비교 기준표(방법 선택 판단 기준)
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | 데이터 타입 | 성능 의도 | 순서 보존 |
| Set | 원시값 적합 | 빠름(O(n)) | 기본적으로 삽입순 보장(ES6)이나 구현 주의 |
| filter(indexOf) | 원시값만 | 작은 배열에 적합 | 원본 순서 보장 |
| reduce+Map | 객체 키 기준 | 유연, O(n) | 원본 순서 보장(구현 따라 다름) |
자주 묻는 질문
Q: Set으로 객체 배열 중복 제거가 안 되는 이유는? A: Set은 객체의 참조값(identity)을 비교합니다. 서로 다른 객체 인스턴스는 내용이 같아도 다른 참조로 간주되어 중복 제거되지 않습니다. 객체는 key를 정의해 Map/Set을 활용하거나 JSON 직렬화/비교 방법을 사용해야 합니다.
Q: 정렬 기반 중복 제거는 언제 유리한가요? A: 메모리 제약이 있고 외부 스트리밍으로 처리해야 할 때 유리합니다. 정렬 후 인접 요소만 비교하면 메모리 사용을 낮추는 트레이드오프가 가능합니다. 단 전체 정렬 비용 O(n log n)을 고려해야 합니다.
Q: 중복 제거 후 원본 배열을 수정해도 되나요? A: 불변성을 지키는 것이 안전합니다. 원본을 수정하면 다른 참조 코드에서 예기치 못한 버그가 발생할 수 있으므로, 가능하면 복사본을 만들어 처리하세요.
Q: 대형 배열(수십만 건)은 어떻게 처리해야 하나요? A: 프론트엔드에서 처리하면 메모리와 성능에 부담이 큽니다. 서버 사이드에서 배치로 처리하거나, 페이징/스트리밍으로 나눠 처리하는 방법을 권장합니다.
정리
- javascript 배열 중복 제거는 원시값과 객체에 따라 접근법이 달라진다.
- 원시값은 Set이 가장 간단하고 빠르다; 객체는 key 기반 Map/Set 또는 filter+seen 패턴 사용.
- 성능, 메모리, 순서 보존 요구를 기준으로 방법을 선택해야 한다.
- 실무 체크리스트로 타입·키·순서·메모리를 점검하고 불변성 유지 권장.
- 대용량 데이터는 서버 처리나 스트리밍/정렬 기반 방법 고려.