문제 상황
여러 학생(student) 객체를 담고 있는 배열이 있다고 가정해 보겠습니다. 각 학생 객체는 여러 속성을 가지며, 그중 하나는 grades라는 이름의 점수 배열입니다.
const arr = [
{
name: "Student 1",
grades: [65, 61, 67, 70]
},
{
name: "Student 2",
grades: [50, 51, 53, 90]
},
{
name: "Student 3",
grades: [0, 20, 40, 60]
}
];이제 이 배열을 순회하면서 grades 배열 안에서 가장 높은 점수를 보유한 학생 객체를 찾는 함수를 만들어야 합니다.
해결 방법: map()과 sort() 활용
가장 직관적인 접근 방식은 다음 두 단계로 나누는 것입니다.
map()으로 각 학생별 최고 점수를 계산합니다.sort()로 내림차순 정렬한 뒤 첫 번째 요소를 선택합니다.
const highestGrades = arr.map((stud) => {
return {
name: stud.name,
// 각 학생의 최고 점수를 구합니다.
highestGrade: Math.max.apply(Math, stud.grades)
};
});
// 내림차순 정렬 후 첫 번째(최고점) 학생 선택
const bestStudent = highestGrades.sort(
(a, b) => b.highestGrade - a.highestGrade
)[0];
console.log(bestStudent.name + " has the highest score of " +
bestStudent.highestGrade);
출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
Student 2 has the highest score of 90
코드 설명
- Math.max.apply(Math, stud.grades):
apply를 사용하면 배열의 요소들을 개별 인수로 전달해 최댓값을 구할 수 있습니다. ES6 이상 환경이라면 전개 연산자를 활용한Math.max(...stud.grades)로 더 간결하게 작성하는 것이 좋습니다. - map(): 원본 배열을 변경하지 않으면서 각 객체를
name과highestGrade를 포함하는 새로운 구조로 변환합니다. - sort(): 비교 함수
(a, b) => b.highestGrade - a.highestGrade로 내림차순 정렬합니다. 정렬 후 첫 번째 요소가 곧 최고 점수를 가진 학생입니다.
대안: reduce()로 한 번의 순회로 해결하기
정렬은 O(n log n)의 시간 복잡도를 가지므로, 데이터가 많다면 reduce()를 사용해 단 한 번의 순회(O(n))만으로 해결하는 편이 더 효율적입니다.
const bestStudent = arr.reduce((best, current) => {
const currentMax = Math.max(...current.grades);
const bestMax = best ? best.highestGrade : -Infinity;
return currentMax > bestMax
? { ...current, highestGrade: currentMax }
: best;
}, null);
console.log(`${bestStudent.name} has the highest score of ${bestStudent.highestGrade}`);
두 방법 모두 동일한 결과를 출력하지만, 대량의 데이터를 처리할 때는 reduce() 기반 방식이 성능 면에서 유리합니다. 상황에 맞게 적절한 방법을 선택하시기 바랍니다.