본문 바로가기
dev/javascript

[javascript] 자바스크립트 배열 중복 제거

by 최연탄 2023. 3. 14.
728x90
반응형

참고: 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);

관련 글

자바스크립트 배열에서 특정 값 삭제

자바스크립트 splice() 사용 방법

자바스크립트 배열 사용 방법

반응형

댓글