문제 상황
다음과 같이 항목 이름을 키로, 숫자를 값으로 가지는 객체 배열이 있다고 가정해 보겠습니다.
const arr = [
{'item1': 144},
{'item2': 0},
{'item3': 366},
{'item4': 15},
{'item6': 366},
{'item7': 19},
{'item8': 211},
{'item9': 121}
];우리가 작성해야 할 것은 이러한 배열을 입력받아 객체들을 'XL', 'L', 'M', 'S' 네 개의 그룹으로 묶어 주는 자바스크립트 함수입니다. 여기서 중요한 점은, 숫자가 절대적인 고정 기준이 아니라 배열 내 최댓값 대비 상대적인 크기를 기준으로 그룹에 배분되어야 한다는 것입니다.
접근 방법
이 문제는 다음 단계로 해결할 수 있습니다.
- 배열의 각 객체에서 첫 번째 키에 해당하는 숫자 값을 추출합니다.
Math.max()를 사용해 전체 값 중 최댓값을 구합니다.- 최댓값을 기준으로 네 등급의 경계값을 정의합니다. — XL: max, L: max × 3/4, M: max ÷ 2, S: max ÷ 4
- 각 숫자가 어느 구간에 속하는지 판별하고, 해당 그룹에 객체의 키 이름을 배정합니다.
구현 코드
const arr = [
{'item1': 144},
{'item2': 0},
{'item3': 366},
{'item4': 15},
{'item6': 366},
{'item7': 19},
{'item8': 211},
{'item9': 121}
];
// 숫자가 속한 구간의 인덱스를 찾는 함수
const compareWithRange = (rangeArr, num) => {
for(let i = 0; i < rangeArr.length; i++){
if(num <= rangeArr[i] && num > rangeArr[i + 1]){
return i;
};
};
// 어떤 구간에도 속하지 않으면 마지막 그룹(S)으로 처리
return rangeArr.length - 1;
}
const groupBySize = (arr = []) => {
// 각 객체에서 숫자 값만 추출
const mapping = arr => arr.map(el => el[Object.keys(el)[0]]);
const max = Math.max(...mapping(arr));
// 최댓값을 기준으로 한 등급별 경계값
const range = {
'XL': max,
'L': (max * 3) / 4,
'M': (max / 2),
'S': (max / 4)
};
const legend = ['XL', 'L', 'M', 'S'];
const res = {};
arr.forEach(el => {
const num = el[Object.keys(el)[0]];
const index = compareWithRange(Object.keys(range).map(key => range[key]), num);
const size = legend[index];
if(res.hasOwnProperty(size)){
res[size].push(Object.keys(el));
}
else{
res[size] = [Object.keys(el)];
}
});
return res;
};
console.log(groupBySize(arr));코드 설명
compareWithRange 함수
경계값 배열과 숫자를 받아, 해당 숫자가 어느 구간에 속하는지 인덱스로 반환합니다. 조건은 num <= 현재 경계값 && num > 다음 경계값이며, 어떤 조건에도 맞지 않는 경우(예: 최솟값 근처의 수)에는 마지막 그룹인 S로 분류됩니다.
groupBySize 함수
Math.max()와 스프레드 연산자(...)를 활용해 배열 전체의 최댓값을 구합니다.- 최댓값을 4등분하여 XL, L, M, S 등급의 경계값을 정의합니다.
forEach로 각 객체를 순회하며 숫자 값의 소속 구간을 판별하고, 결과 객체(res)에 그룹별로 키 이름을 누적 저장합니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
{
M: [ [ 'item1' ], [ 'item9' ] ],
S: [ [ 'item2' ], [ 'item4' ], [ 'item7' ] ],
XL: [ [ 'item3' ], [ 'item6' ] ],
L: [ [ 'item8' ] ]
}결과 해석
이 예제에서 최댓값은 366이므로 각 등급의 경계는 다음과 같습니다.
- XL: 274.5 초과 ~ 366 이하 → item3(366), item6(366)
- L: 183 초과 ~ 274.5 이하 → item8(211)
- M: 91.5 초과 ~ 183 이하 → item1(144), item9(121)
- S: 0 이상 ~ 91.5 이하 → item2(0), item4(15), item7(19)
이처럼 데이터에 포함된 최댓값을 기준으로 상대적인 크기에 따라 값을 자동으로 등급화하면, 데이터의 실제 분포에 유연하게 대응하는 동적 분류 로직을 만들 수 있습니다. 차트 시각화, 성능 등급 산정, 제품 사이즈 분류 등 다양한 상황에 응용할 수 있는 유용한 패턴입니다.