최빈값은 주어진 값 중에서 가장 자주 나오는 값을 의미합니다. 정수 배열 array가 매개변수로 주어질 때, 최빈값을 return 하도록 solution 함수를 완성해보세요. 최빈값이 여러 개면 -1을 return 합니다.
제한사항
function solution(array) {
// Map() -> key, value 값 저장
let counting = new Map();
for (let i = 0; i < array.length; i++) {
if (!counting.has(array[i])) {
counting.set(array[i], 1);
} else if (counting.has(array[i])) {
counting.set(array[i], counting.get(array[i]) + 1);
}
}
let maxCount = 0; // 최대 빈도수 기록
let modes = []; // 최빈값 저장 배열
counting.forEach((count, number) => {
if (count > maxCount) {
maxCount = count; // 최대 빈도수 갱신
modes = [number]; // 최빈값 배열 초기화
} else if (count === maxCount) {
modes.push(number); // 현재 빈도수가 최대 빈도수와 같다면 최빈값 배열에 추가
}
});
// 최빈값이 여러개면 -1, 하나라면 그 값을 반환
if (modes.length > 1) {
return -1;
} else return modes[0];
}
counting이라는 Map 객체를 생성하여 배열의 각 요소의 등장 횟수를 저장한다
주어진 배열 array를 순회하면서 각 요소가 counting에 존재하는지 확인한다.
maxCount는 지금까지 발견된 요소의 최대 등장횟수이다. modes 배열에는 최빈값을 저장한다.
counting을 순회하면서 각 요소의 등장 횟수(count)와 요소(number)를 확인한다. 현재 요소의 등장 횟수가 maxCount보다 크다면 갱신, modes 배열을 현재 요소만 포함하도록 초기화한다. 현재 요소의 등장 횟수가 maxCount와 같다면 현재 요소를 modes 배열에 추가한다.
최종적으로 modes 배열의 길이를 확인하여 1보다 크다면 -1을 반환하고 그렇지 않다면 modes[0]을 반환한다.
Map
객체는 키-값 쌍과 키의 원래 삽입 순서를 기억한다. 키에 대한 다양한 자료형을 사용할 수 있다.
clear()
: Map
객체의 모든 요소 제거map1.clear();
delete()
: Map
객체에서 특정 요소 제거map1.delete('bar');
entries()
: 새 반복자 객체를 반환forEach()
: 삽입 순서에 따라 Map
객체의 각 키/값 쌍마다 한 번씩 제공된 함수를 실행get()
: Map
객체에서 특정 요소 반환set()
: Map
객체에서 주어진 키와 값을 추가하거나 업데이트 has()
: 주어진 키에 해당하는 요소가 존재 여부를 가리키는 불리언 값을 반환keys()
: 배열에서 각 인덱스의 키를 포함하는 새로운 맵 반복자 객체를 반환values()
: 배열의 각 아이템의 값을 순회하는 새로운 맵 반복자 객체를 반환
forEach()
메서드는 각 배열 요소에 대해 제공된 함수를 한 번씩 실행한다.
forEach(callbackFn)
forEach(callbackFn, thisArg)
매개변수
callbackFn
- 배열의 각 요소에 대해 실행할 함수입니다. 반환값은 사용되지 않습니다. 함수는 다음 인수를 사용하여 호출됩니다.
- `element` -배열에서 처리 중인 현재 요소.
- `index` -배열에서 처리 중인 현재 요소의 인덱스.
- `array` - forEach()를 호출한 배열.
thisArg Optional
- callbackFn을 실행할 때 this 값으로 사용할 값입니다. 순회 메서드를 참조하세요.
반환 값
없음 (undefined).
for 루프를 forEach()로 바꾸기
const items = ["item1", "item2", "item3"];
const copyItems = [];
// 전
for (let i = 0; i < items.length; i++) {
copyItems.push(items[i]);
}
// 후
items.forEach((item) => {
copyItems.push(item);
});
function solution(array) {
let m = new Map();
for (let n of array) m.set(n, (m.get(n) || 0)+1);
m = [...m].sort((a,b)=>b[1]-a[1]);
return m.length === 1 || m[0][1] > m[1][1] ? m[0][0] : -1;
}
Map 객체 m을 생성
배열 array를 순회하면서 각 요소 n에 대해 해당 요소의 현재 등장 횟수를 가져온다. 만약 해당 요소가 Map에 존재하지 않으면 undefined를 반환하기 때문에 0을 사용하여 0으로 대체한 다음 1을 더하여 새로운 등장 횟수를 m.set(n, (m.get(n) || 0) + 1)
로 Map에 저장한다.
m을 배열로 변환한다. Map 객체는 기본적으로 키-밸류 쌍의 배열로 변환된다.
변환된 배열을 sort() 함수를 통해 내림차순으로 정렬한다. b[1] - a[1]
은 등장 횟수가 큰 순서대로 정렬한다.
정렬된 배열 m의 길이가 1인 경우, 또는 등장 횟수가 가장 많은 첫 번째 요소의 등장 횟수(m[0][1]
)가 두 번째 요소의 등장 횟수(m[1][1]
)보다 큰 경우 최빈값은 유일하므로 m[0][0]
를 반환, 그렇지 않으면 최빈값이 여러개 존재하므로 -1을 반환한다.
const solution = (array) => {
const counter = array.reduce((acc, cur) => ({
...acc,
[cur]: (acc[cur] || 0) + 1
}), {})
const items = Object.keys(counter).map((key) => [
Number(key), counter[key]
]).sort((a, b) => b[1] - a[1])
if (items[0][1] === items?.[1]?.[1]) {
return -1
}
return items[0][0];
}
reduce()를 사용하여 배열의 각 요소 cur에 대해 등장 횟수를 계산한다.
acc는 누적 객체를 의미하고, 초기값은 빈 객체 {}
이다.
새로운 객체를 반환할 때, 현재 요소 cur의 등장 횟수를 증가시킨다. 만약 cur가 객체에 존재하지 않으면 0으로 초기화하고 그렇지 않으면 기존 값에 1을 더한다.
Object.keys(counter)
를 사용하여 counter의 키를 배열로 가져온다.
map()을 사용하여 각 키를 [key, value]쌍의 배열로 변환한다.
변환된 배열을 등장 횟수(value)를 기준으로 내림차순 정렬한다.
정렬된 배열 items에서 가장 높은 등장 횟수를 가진 첫 번째 요소(items[0][1]
)와 두 번째 요소(items?.[1]?.[1]
)의 등장 횟수를 비교한다.
두 값이 같으면 최빈값이 여러개 존재하므로 -1을 반환, 그렇지 않으면 최빈값은 유일하므로 첫 번째 요소의 키(items[0][0]
을 반환)
이 문제는 푸는데 시간이 꽤 오래걸렸고 다른 사람의 풀이도 이해하는데 시간이 꽤 걸렸던 것으로 기억한다. Map을 사용해서 푼 첫 번째 문제였고, 언젠가 다시 돌아보며 기억하면 좋을 것 같아 기록으로 남김! 미루고 미루다가 이제서야 올린다.