문제 정의
여러 학생의 과목별 시험 점수가 아래와 같이 배열 안에 중첩된 형태(배열의 배열)로 저장되어 있습니다. 각 내부 배열은 [과목명, 학생 이름, 점수] 순서로 구성됩니다.
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
}
]
}
]
코드 동작 원리
핵심 로직을 단계별로 살펴보겠습니다.
- 구조 분해 할당:
const [sub, name, score] = val;로 각 내부 배열에서 과목명, 이름, 점수를 한 번에 추출합니다. - 과목 검색:
findIndex()로 누적 배열(acc)에 같은 과목의 객체가 이미 존재하는지 확인합니다. - 점수 비교: 과목이 존재하면 새 점수를 기존 최고 점수와 비교합니다. 더 높으면 Top 배열을 새 학생으로 교체하고, 점수가 같으면 동점자로 추가합니다.
- 신규 과목 등록: 아직 없는 과목이라면 새 객체를 만들어 acc에 추가합니다.
- 누적값 반환: reduce 콜백이 항상 acc를 반환하므로, 최종적으로 과목별 최고 득점자 정보가 담긴 배열이 완성됩니다.
이 방식은 그룹화와 최댓값 계산을 동시에 처리하므로 O(n)의 시간 복잡도로 효율적으로 동작합니다.