문제 정의
다음과 같이 학생들의 과목별 점수가 담긴 2차원 배열이 있다고 가정해 보겠습니다.
const arr = [ ["English", 52], ["Hindi", 154], ["Hindi", 241], ["Spanish", 10], ["French", 65], ["German", 98], ["Russian", 10] ];
여기서 해야 할 일은 이러한 배열을 입력받아 객체의 객체(object of objects) 형태로 반환하는 JavaScript 함수를 작성하는 것입니다.
반환되는 객체는 각 고유한 과목마다 하나의 하위 객체를 가져야 하며, 각 하위 객체에는 다음 세 가지 정보가 포함되어야 합니다.
- count: 해당 과목이 배열에 등장한 횟수
- total: 해당 과목 점수의 총합
- average: 해당 과목 점수의 평균
구현 코드
배열의 내장 메서드인 reduce()를 사용하면 별도의 반복문 없이도 간결하게 그룹화 로직을 구현할 수 있습니다.
const arr = [
["English", 52],
["Hindi", 154],
["Hindi", 241],
["Spanish", 10],
["French", 65],
["German", 98],
["Russian", 10]
];
const groupSubjects = arr => {
const grouped = arr.reduce((acc, val) => {
const [key, total] = val;
// 아직 없는 과목이라면 초기 객체 생성
if (!Object.prototype.hasOwnProperty.call(acc, key)) {
acc[key] = { count: 0, total: 0 };
}
const subject = acc[key];
subject.count++; // 등장 횟수 증가
subject.total += total; // 점수 누적
subject.average = subject.total / subject.count; // 평균 계산
return acc;
}, {});
return grouped;
};
console.log(groupSubjects(arr));코드 동작 원리
reduce()의 초기 누적값으로 빈 객체{}를 지정합니다.- 순회 중인 항목에서 과목명(key)과 점수(total)를 구조 분해 할당으로 추출합니다.
hasOwnProperty()로 해당 과목이 누적 객체에 존재하지 않으면count와total이 0인 초기 객체를 생성합니다.- 항목을 처리할 때마다
count를 1 증가시키고total에 점수를 더합니다. - 평균은 누적된 총합을 등장 횟수로 나눈 값으로 매번 갱신합니다.
주의: 평균을 계산할 때는 현재 항목의 점수가 아니라 반드시 누적된 subject.total을 사용해야 합니다. 그렇지 않으면 마지막에 처리된 항목의 점수를 기준으로 잘못된 평균이 계산됩니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
{
English: { count: 1, total: 52, average: 52 },
Hindi: { count: 2, total: 395, average: 197.5 },
Spanish: { count: 1, total: 10, average: 10 },
French: { count: 1, total: 65, average: 65 },
German: { count: 1, total: 98, average: 98 },
Russian: { count: 1, total: 10, average: 10 }
}"Hindi"는 두 번 등장했으므로 count는 2, total은 154 + 241 = 395, 평균은 395 ÷ 2 = 197.5로 올바르게 계산된 것을 확인할 수 있습니다. 이처럼 reduce() 하나만으로 배열 데이터를 원하는 기준별로 손쉽게 그룹화하고 통계까지 산출할 수 있습니다.