참고: https://www.javascripttutorial.net/array/javascript-remove-duplicates-from-array/
이 포스트에서는 JavaScript의 배열에서 중복된 항목을 제거하는 방법을 알아보겠습니다.
1. Set를 사용하여 배열에서 중복 제거
Set 객체는 고유한 값의 집합을 가집니다. 배열에서 중복 항목을 제거하려면:
- 먼저 중복된 배열을 Set로 변환합니다. 새 Set는 중복 요소를 암묵적으로 제거합니다.
- 그다음 Set를 다시 배열로 변환합니다.
다음 예제에서는 Set를 사용하여 배열에서 중복 항목을 제거합니다:
let chars = ['A', 'B', 'A', 'C', 'B'];
let uniqueChars = [...new Set(chars)];
console.log(uniqueChars);
2. indexOf()와 filter() 메소드를 사용하여 배열에서 중복 제거
indexOf() 메소드는 배열에서 첫 번째로 찾은 값에 대한 인덱스를 반환합니다. 예:
let chars = ['A', 'B', 'A', 'C', 'B'];
let index = chars.indexOf('B');
console.log(index); // 1
이를 이용해 중복된 항목의 인덱스는 indexOf()의 값과 다릅니다:
let chars = ['A', 'B', 'A', 'C', 'B'];
chars.forEach((c, index) => {
console.log(`${c} - ${index} - ${chars.indexOf(c)}`);
});
여기서 중복된 항목을 제거하려면 filter() 메소드를 사용하여 인덱스가 indexOf()의 값과 일치하는 요소만 남기면 됩니다:
let chars = ['A', 'B', 'A', 'C', 'B'];
let uniqueChars = chars.filter((c, index) => {
return chars.indexOf(c) === index;
});
console.log(uniqueChars);
중복된 값들을 얻고 싶으면 조건문을 뒤집으면 됩니다:
let chars = ['A', 'B', 'A', 'C', 'B'];
let dupChars = chars.filter((c, index) => {
return chars.indexOf(c) !== index;
});
console.log(dupChars);
3. forEach()와 include()를 사용하여 배열에서 중복 제거
include() 메소드는 배열에 항목이 있을 경우 true를 리턴하고, 없으면 false를 리턴합니다.
다음 예제는 배열의 요소를 루프돌고 새 배열에 아직 존재하지 않는 요소만 새 배열에 추가합니다:
let chars = ['A', 'B', 'A', 'C', 'B'];
let uniqueChars = [];
chars.forEach((c) => {
if (!uniqueChars.includes(c)) {
uniqueChars.push(c);
}
});
console.log(uniqueChars);
4. 객체의 특정 속성만 비교해서 중복제거
다음과 같은 객체의 배열이 있다고 가정해 보겠습니다:
const members = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 1, name: 'Johnny' },
{ id: 4, name: 'Alice' },
];
첫 번째 요소의 id는 세 번째 요소와 동일합니다. 이러한 목록에서 중복을 제거하려면 다음과 같이 할 수 있습니다:
const unique = [...new Map(members.map((m) => [m.id, m])).values()];
console.log(unique);
위의 코드가 작동되는 방법은 먼저 map() 메소드를 사용하여 원래 배열에서 새 배열을 만듭니다:
members.map((m) => [m.id, m])
이는 배열의 배열을 리턴합니다. 중첩된 각 배열에는 id와 해당 객체의 값이 포함됩니다:
[
[ 1, { id: 1, name: 'John' } ],
[ 2, { id: 2, name: 'Jane' } ],
[ 1, { id: 1, name: 'Johnny' } ],
[ 4, { id: 4, name: 'Alice' } ]
]
다음으로 Map() 객체를 생성하여 중복을 제거하는 것 입니다:
const newMap = new Map(newArray);
console.log(newMap);
위 코드의 실행 결과는:
Map(3) {
1 => { id: 1, name: 'Johnny' },
2 => { id: 2, name: 'Jane' },
4 => { id: 4, name: 'Alice' }
}
Map 객체의 키는 고유해야 하므로 배열의 배열에서 Map을 생성하면 키 당 중복된 객체(이 경우 id)는 제거됩니다.
세 번째로 values() 메소드를 호출하여 Map의 iterator를 가져옵니다:
const iterator = newMap.values();
console.log(iterator);
// [Map Iterator] {
// { id: 1, name: 'Johnny' },
// { id: 2, name: 'Jane' },
// { id: 4, name: 'Alice' }
// }
마지막으로 스프레드 연산자(...)를 사용해 iterator를 배열로변환합니다:
const uniqueMembers = [...iterator];
console.log(uniqueMembers);
// [
// { id: 1, name: 'Johnny' },
// { id: 2, name: 'Jane' },
// { id: 4, name: 'Alice' }
// ]
전체 코드를 보면:
const members = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 1, name: 'Johnny' },
{ id: 4, name: 'Alice' },
];
const newArray = members.map((m) => [m.id, m]);
const newMap = new Map(newArray);
const iterator = newMap.values();
const unique = [...iterator];
console.log(unique);
여기서 다음 네 줄의 코드를:
const newArray = members.map((m) => [m.id, m]);
const newMap = new Map(newArray);
const iterator = newMap.values();
const unique = [...iterator];
다음과 같이 축약할 수 있습니다:
const unique = [...new Map(members.map((m) => [m.id, m])).values()];
이를 적용하면:
const members = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 1, name: 'Johnny' },
{ id: 4, name: 'Alice' },
];
const unique = [...new Map(members.map((m) => [m.id, m])).values()];
console.log(unique);
다음의 uniqueBy() 함수는 객체의 배열과 검색할 속성 키를 받아 고유한 값만 리턴합니다:
const uniqueBy = (arr, prop) => {
return [...new Map(arr.map((m) => [m[prop], m])).values()];
};
예를 들면 uniqueBy() 함수를 사용해 다음과 같이 중복을 제거할 수 있습니다:
const members = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 1, name: 'Johnny' },
{ id: 4, name: 'Alice' },
];
const uniqueBy = (arr, prop) => {
return [...new Map(arr.map((m) => [m[prop], m])).values()];
};
console.log(uniqueBy(members, 'id'));
5. 여러개의 속성으로 객체 배열에서 중복 제거
다음 unique() 함수는 객체 배열에서 중복 항목을 제거합니다. 중복 제거 로직은 콜백 함수에 의해 지정됩니다:
function unique(a, fn) {
if (a.length === 0 || a.length === 1) {
return a;
}
if (!fn) {
return a;
}
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j < a.length; j++) {
if (fn(a[i], a[j])) {
a.splice(i, 1);
}
}
}
return a;
}
작동 방법은 먼저 배열 항목이 없거나 하나만 있을 경우 넘어갑니다:
if (a.length === 0 || a.length === 1) {
return a;
}
다음으로 콜백 함수가 지정되지 않았다면 또 넘어갑니다:
if (!fn) {
return a;
}
세 번째로 입력 배열의 요소에 대해 두 번 루프돌며 첫 번째 요소를 다른 요소와 연속적으로 비교합니다. 두 요소를 콜백 함수(fn)에서 true로 리턴하면 splice() 메소드를 사용하여 배열에서 해당 요소를 제거합니다:
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j < a.length; j++) {
if (fn(a[i], a[j])) {
a.splice(i, 1);
}
}
}
다음 예제는 unique() 함수를 만들어 member 배열에서 id와 name 속성 모두의 중복을 제거합니다:
function unique(a, fn) {
if (a.length === 0 || a.length === 1) {
return a;
}
if (!fn) {
return a;
}
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j < a.length; j++) {
if (fn(a[i], a[j])) {
a.splice(i, 1);
}
}
}
return a;
}
const members = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 1, name: 'John' },
{ id: 4, name: 'Joe' },
{ id: 5, name: 'Joe' },
];
const uniqueMembers = unique(
members,
(a, b) => {
if (!a || !b) {
return true;
}
return (a.id === b.id) & (a.name === b.name);
}
);
console.log(uniqueMembers);
관련 글
'dev > javascript' 카테고리의 다른 글
[javascript] 자바스크립트 스크롤 캔버스 애니메이션 (애플 홈페이지) (5) | 2023.03.15 |
---|---|
[javascript] 자바스크립트 문자열 찾기 (5) | 2023.03.15 |
[javascript] 자바스크립트 두 좌표 사이 거리구하기 (3) | 2023.03.12 |
[javascript] 자바스크립트 스크롤 애니메이션 (2) | 2023.03.12 |
[javascript] CSS scroll indicator (수평 스크롤바) (0) | 2023.03.12 |
댓글