문제 소개
숫자나 문자열 리터럴로 이루어진 배열이 있고, 그중 일부 값은 중복되어 있다고 가정해 보겠습니다. 이번 글에서는 배열 안에서 가장 많이 등장하는 요소를 반환하는 함수를 작성하는 방법을 알아보겠습니다.
예를 들어 입력 배열이 다음과 같다면,
const input = ['a', 'v', 'k', 'f', 'a', 'f', 's', 'd', 'd', 'f', 'a', 'j', 'a'];
출력 결과는 다음과 같아야 합니다.
'a'
그 이유는 'a'가 배열에서 총 4번으로 가장 많이 반복되기 때문입니다.
Map()을 활용한 해결 방법
이 문제는 Map() 객체를 활용하면 깔끔하게 해결할 수 있습니다. 접근 방식은 다음과 같습니다.
- 배열을 순회하면서 각 요소와 그 등장 횟수를
Map에 기록합니다. - 모든 요소의 개수를 센 후, 가장 많은 횟수를 가진 요소를 반환합니다.
예제 코드
const input = ['m', 'a', 'v', 'k', 'f', 'a', 'f', 's', 'd', 'd', 'f', 'a', 'j', 'a'];
const findMaximum = arr => {
// 1단계: 각 요소의 등장 횟수를 Map에 저장
const map = arr.reduce((acc, val) => {
let count = acc.get(val);
if(count){
acc.set(val, ++count);
} else {
acc.set(val, 1);
};
return acc;
}, new Map());
// 2단계: 개수가 가장 큰 항목 찾기
return Array.from(map).reduce((acc, val) => {
if(val[1] > acc[1]){
return val;
};
return acc;
}, [0, 0])[0];
};
console.log(findMaximum(input));코드 동작 원리
첫 번째 단계(빈도 계산)에서는 reduce() 메서드로 배열을 순회하며 각 요소의 등장 횟수를 Map에 누적합니다. 이미 존재하는 요소라면 카운트를 1 증가시키고, 처음 등장한 요소라면 1로 초기화합니다.
두 번째 단계(최대값 탐색)에서는 Array.from(map)을 사용해 Map을 [요소, 개수] 형태의 배열로 변환한 뒤, 다시 reduce()를 적용해 개수가 가장 큰 항목을 찾습니다. 최종적으로 해당 항목의 첫 번째 값, 즉 요소 자체만 반환됩니다.
실행 결과
콘솔 출력 결과는 다음과 같습니다.
a
이처럼 Map()과 reduce()를 조합하면 별도의 중첩 반복문 없이 시간 복잡도 O(n)으로 배열 내 최다 빈출 요소를 효율적으로 구할 수 있습니다.