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

JavaScript에서 숫자 값의 상대적 크기에 따라 객체를 XL·L·M·S 그룹으로 분류하는 알고리즘

문제 상황

다음과 같이 항목 이름을 키로, 숫자를 값으로 가지는 객체 배열이 있다고 가정해 보겠습니다.

const arr = [
    {'item1': 144},
    {'item2': 0},
    {'item3': 366},
    {'item4': 15},
    {'item6': 366},
    {'item7': 19},
    {'item8': 211},
    {'item9': 121}
];

우리가 작성해야 할 것은 이러한 배열을 입력받아 객체들을 'XL', 'L', 'M', 'S' 네 개의 그룹으로 묶어 주는 자바스크립트 함수입니다. 여기서 중요한 점은, 숫자가 절대적인 고정 기준이 아니라 배열 내 최댓값 대비 상대적인 크기를 기준으로 그룹에 배분되어야 한다는 것입니다.

접근 방법

이 문제는 다음 단계로 해결할 수 있습니다.

  1. 배열의 각 객체에서 첫 번째 키에 해당하는 숫자 값을 추출합니다.
  2. Math.max()를 사용해 전체 값 중 최댓값을 구합니다.
  3. 최댓값을 기준으로 네 등급의 경계값을 정의합니다. — XL: max, L: max × 3/4, M: max ÷ 2, S: max ÷ 4
  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)

이처럼 데이터에 포함된 최댓값을 기준으로 상대적인 크기에 따라 값을 자동으로 등급화하면, 데이터의 실제 분포에 유연하게 대응하는 동적 분류 로직을 만들 수 있습니다. 차트 시각화, 성능 등급 산정, 제품 사이즈 분류 등 다양한 상황에 응용할 수 있는 유용한 패턴입니다.