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

JavaScript – 과목별 최고 점수 학생을 찾아 객체 배열로 반환하기

문제 정의

여러 학생의 과목별 시험 점수가 아래와 같이 배열 안에 중첩된 형태(배열의 배열)로 저장되어 있습니다. 각 내부 배열은 [과목명, 학생 이름, 점수] 순서로 구성됩니다.

const arr = [
    ['Math', 'John', 100],
    ['Math', 'Jake', 89],
    ['Math', 'Amy', 93],
    ['Science', 'Jake', 89],
    ['Science', 'John', 89],
    ['Science', 'Amy', 83],
    ['English', 'John', 82],
    ['English', 'Amy', 81],
    ['English', 'Jake', 72]
];

이 데이터를 입력받아 과목별로 하나의 객체를 생성하고, 그 안에 해당 과목의 최고 득점자 정보를 담은 객체 배열을 반환하는 함수를 작성하는 것이 목표입니다. 최고 점수가 여러 명일 경우에는 동점자를 모두 포함해야 합니다.

원하는 출력 결과는 다음과 같습니다.

[
    {
        "Subject": "Math",
        "Top": [
            { "name": "John", "score": 100 }
        ]
    },
    {
        "Subject": "Science",
        "Top": [
            { "name": "Jake", "score": 89 },
            { "name": "John", "score": 89 }
        ]
    },
    {
        "Subject": "English",
        "Top": [
            { "name": "John", "score": 82 }
        ]
    }
]

Science 과목에서 Jake와 John이 동점(89점)이므로 두 학생 모두 Top 배열에 포함되는 것을 확인할 수 있습니다.

구현 코드

이 문제는 배열 메서드인 reduce()를 활용하면 배열을 한 번만 순회하면서 해결할 수 있습니다. 전체 구현 코드는 다음과 같습니다.

const groupScore = arr => {
    return arr.reduce((acc, val) => {
        const [sub, name, score] = val;
        const ind = acc.findIndex(el => el['Subject'] === val[0]);
        if (ind !== -1) {
            if (score > acc[ind]['Top'][0]['score']) {
                acc[ind]['Top'] = [{ name: name, score: score }];
            } else if (score === acc[ind]['Top'][0]['score']) {
                acc[ind]['Top'].push({ name: name, score: score });
            }
        } else {
            acc.push({
                Subject: sub,
                Top: [{ name: name, score: score }]
            });
        }
        return acc;
    }, []);
};
console.log(JSON.stringify(groupScore(arr), undefined, 4));

실행 결과

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

[
    {
        "Subject": "Math",
        "Top": [
            {
                "name": "John",
                "score": 100
            }
        ]
    },
    {
        "Subject": "Science",
        "Top": [
            {
                "name": "Jake",
                "score": 89
            },
            {
                "name": "John",
                "score": 89
            }
        ]
    },
    {
        "Subject": "English",
        "Top": [
            {
                "name": "John",
                "score": 82
            }
        ]
    }
]

코드 동작 원리

핵심 로직을 단계별로 살펴보겠습니다.

  1. 구조 분해 할당: const [sub, name, score] = val;로 각 내부 배열에서 과목명, 이름, 점수를 한 번에 추출합니다.
  2. 과목 검색: findIndex()로 누적 배열(acc)에 같은 과목의 객체가 이미 존재하는지 확인합니다.
  3. 점수 비교: 과목이 존재하면 새 점수를 기존 최고 점수와 비교합니다. 더 높으면 Top 배열을 새 학생으로 교체하고, 점수가 같으면 동점자로 추가합니다.
  4. 신규 과목 등록: 아직 없는 과목이라면 새 객체를 만들어 acc에 추가합니다.
  5. 누적값 반환: reduce 콜백이 항상 acc를 반환하므로, 최종적으로 과목별 최고 득점자 정보가 담긴 배열이 완성됩니다.

이 방식은 그룹화와 최댓값 계산을 동시에 처리하므로 O(n)의 시간 복잡도로 효율적으로 동작합니다.