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

JavaScript 배열에서 동일한 요소를 그룹으로 묶는 방법

문제 상황

알파벳 문자들이 담긴 배열이 있고, 그중 일부 알파벳은 여러 번 반복되어 있다고 가정해 보겠습니다.

const arr = [
  'a','a','a','a','d','e','e','f','h','h','h','i','l','m','n',
  'r','s','s','t','u','v','y','y'
];

이런 배열을 입력받아 동일한 알파벳끼리 각각의 하위 배열(subarray)로 묶어주는 JavaScript 함수를 작성해야 합니다.

즉, 위 배열에 대해 함수가 반환해야 하는 결과는 다음과 같습니다.

const output = [
  ['a','a','a','a'], ['d'], ['e','e'], ['f'], ['h','h','h'],
  ['i'], ['l'], ['m'], ['n'], ['r'], ['s','s'], ['t'], ['u'],
  ['v'], ['y','y']
];

해결 방법: reduce와 해시 객체 활용하기

이 문제는 reduce() 메서드와 해시(hash) 객체를 조합하면 깔끔하게 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.

  • 해시 객체: 각 알파벳이 결과 배열에서 몇 번째 인덱스(그룹)에 속하는지 기록합니다.
  • reduce 누적기(res): 실제 그룹화된 결과 배열을 쌓아갑니다.

요소를 순회하면서 처음 등장한 알파벳이라면 새로운 하위 배열을 만들고, 이미 등장한 적이 있다면 해시에 저장된 인덱스를 이용해 해당 그룹에 요소를 추가(push)하면 됩니다.

코드 예제

const arr = [
  'a','a','a','a','d','e','e','f','h','h','h','i','l','m','n',
  'r','s','s','t','u','v','y','y'
];

const bringAlong = (arr = []) => {
  const hash = {};
  return arr.reduce(function(res, e) {
    if (hash[e] === undefined)
      hash[e] = res.push([e]) - 1; // 새 그룹 생성 후 인덱스 저장
    else
      res[hash[e]].push(e);        // 기존 그룹에 추가
    return res;
  }, []);
};

console.log(bringAlong(arr));

실행 결과

위 코드를 실행하면 콘솔에 다음과 같이 출력됩니다.

[
  [ 'a', 'a', 'a', 'a' ],
  [ 'd' ],
  [ 'e', 'e' ],
  [ 'f' ],
  [ 'h', 'h', 'h' ],
  [ 'i' ],
  [ 'l' ],
  [ 'm' ],
  [ 'n' ],
  [ 'r' ],
  [ 's', 's' ],
  [ 't' ],
  [ 'u' ],
  [ 'v' ],
  [ 'y', 'y' ]
]

동작 원리 정리

  1. 배열의 각 요소를 reduce()로 순회합니다.
  2. 현재 요소가 해시 객체에 없으면, 빈 하위 배열 하나를 결과에 추가하고 그 인덱스를 해시에 기록합니다.
  3. 이미 해시에 존재하는 요소라면, 기록된 인덱스 위치의 하위 배열에 요소를 추가합니다.
  4. 모든 순회가 끝나면 동일한 값끼리 묶인 2차원 배열이 완성됩니다.

이 방식은 배열을 한 번만 순회하므로 시간 복잡도가 O(n)으로 효율적이며, 숫자·문자열 등 다양한 타입의 배열에도 그대로 응용할 수 있다는 장점이 있습니다.