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

JavaScript 배열에서 중복 값만 골라 한 번씩 추출하는 방법

배열 안에 같은 값이 여러 번 반복해서 등장하는 경우가 종종 있습니다. 예를 들어 다음과 같은 숫자 배열을 살펴보겠습니다.

const arr = [1, 4, 3, 3, 1, 3, 2, 4, 2, 1, 4, 4];

이 배열에는 1이 세 번, 4가 네 번, 3이 세 번, 2가 두 번씩 등장합니다. 여기서 만들고자 하는 JavaScript 함수는 이 배열에서 두 번 이상 나타난 값(중복 값)만 골라내고, 각 값을 딱 한 번만 결과에 포함하는 것입니다.

따라서 위 배열에 대한 기대 출력은 다음과 같습니다.

const output = [1, 4, 3, 2];

기본 구현: indexOf와 lastIndexOf 활용

핵심 아이디어는 간단합니다. 어떤 요소의 첫 번째 인덱스(indexOf)와 마지막 인덱스(lastIndexOf)가 서로 다르다면, 그 값은 배열 안에서 두 번 이상 등장한 중복 값이라는 의미입니다. 여기에 이미 결과 배열에 담겼는지 확인하는 includes 검사를 더하면 됩니다.

const arr = [1, 4, 3, 3, 1, 3, 2, 4, 2, 1, 4, 4];

const removeDuplicate = arr => {
  const res = [];
  for (let i = 0; i < arr.length; i++) {
    // indexOf와 lastIndexOf가 다르면 중복 값
    if (arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i])) {
      if (!res.includes(arr[i])) {
        res.push(arr[i]);
      }
    }
  }
  return res;
};

console.log(removeDuplicate(arr));

실행 결과

콘솔에 출력되는 결과는 다음과 같습니다.

[1, 4, 3, 2]

출력 순서는 각 값이 원본 배열에서 처음 등장한 순서를 그대로 따릅니다.

더 간결한 대안: filter와 Set 조합

같은 로직은 filterSet을 활용하면 훨씬 짧은 코드로 표현할 수 있습니다. 먼저 filter로 중복 값만 걸러낸 뒤, Set으로 겹치는 값을 제거하고 전개 연산자(spread)로 다시 배열로 변환합니다.

const removeDuplicate = arr =>
  [...new Set(arr.filter(v => arr.indexOf(v) !== arr.lastIndexOf(v)))];

console.log(removeDuplicate(arr)); // [1, 4, 3, 2]

성능 개선 팁: Map으로 등장 횟수 세기

위 방식들은 indexOf, lastIndexOf, includes가 모두 배열을 처음부터 끝까지 탐색하므로 전체 시간 복잡도가 O(n²)입니다. 데이터 양이 많다면 Map으로 각 값의 등장 횟수를 한 번에 집계한 후 필터링하면 O(n)으로 최적화할 수 있습니다.

const removeDuplicate = arr => {
  const count = new Map();
  for (const v of arr) {
    count.set(v, (count.get(v) || 0) + 1);
  }
  return [...count].filter(([, c]) => c > 1).map(([v]) => v);
};

console.log(removeDuplicate(arr)); // [1, 4, 3, 2]

상황에 맞는 방법을 선택하면 되는데, 코드 가독성이 중요하다면 filter + Set 조합이, 대용량 데이터 처리 성능이 중요하다면 Map 기반 접근이 적합합니다.