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

JavaScript로 각 학생별 상위 N개 점수의 평균 구하기

문제 소개

여러 명의 학생 정보와 일정 기간 동안 획득한 점수가 담긴 객체 배열이 있다고 가정해 보겠습니다. 각 객체는 학생의 고유 ID(id)와 점수(score)를 포함하고 있으며, 같은 학생이 여러 번 등장할 수 있습니다.

const marks = [
  { id: 231, score: 34 },
  { id: 233, score: 37 },
  { id: 231, score: 31 },
  { id: 233, score: 39 },
  { id: 231, score: 44 },
  { id: 233, score: 41 },
  { id: 231, score: 38 },
  { id: 231, score: 31 },
  { id: 233, score: 29 },
  { id: 231, score: 34 },
  { id: 233, score: 40 },
  { id: 231, score: 31 },
  { id: 231, score: 30 },
  { id: 233, score: 38 },
  { id: 231, score: 43 },
  { id: 233, score: 42 },
  { id: 233, score: 28 },
  { id: 231, score: 33 },
];

우리가 작성해야 할 함수는 다음 두 가지 인자를 받습니다.

  • 첫 번째 인자: 위와 같은 학생 점수 배열
  • 두 번째 인자: 각 학생별로 사용할 상위 점수의 개수를 나타내는 숫자(num)

함수는 각 고유한 학생에 대해 score 속성을 기준으로 가장 높은 점수 num개를 선택하고, 선택된 점수들의 평균을 계산해야 합니다. 만약 어떤 학생의 기록 수가 num보다 적다면, 해당 학생이 가진 모든 기록을 대상으로 평균을 구하면 됩니다. 최종적으로 함수는 학생 ID를 키로, 평균 점수를 값으로 갖는 객체를 반환해야 합니다.

접근 방법

이 문제는 크게 세 단계로 나누어 해결할 수 있습니다.

  1. 그룹화: 배열을 한 번 순회하면서 학생 ID별로 점수를 모읍니다.
  2. 정렬 및 추출: 각 학생의 점수 배열을 내림차순으로 정렬한 뒤, 앞에서 num개만 잘라냅니다.
  3. 평균 계산: 잘라낸 점수들의 합을 개수로 나누어 평균을 구하고, 결과 객체에 학생 ID와 함께 저장합니다.

구현 코드

위 접근 방식을 코드로 구현하면 다음과 같습니다.

const marks = [
  { id: 231, score: 34 },
  { id: 233, score: 37 },
  { id: 231, score: 31 },
  { id: 233, score: 39 },
  { id: 231, score: 44 },
  { id: 233, score: 41 },
  { id: 231, score: 38 },
  { id: 231, score: 31 },
  { id: 233, score: 29 },
  { id: 231, score: 34 },
  { id: 233, score: 40 },
  { id: 231, score: 31 },
  { id: 231, score: 30 },
  { id: 233, score: 38 },
  { id: 231, score: 43 },
  { id: 233, score: 42 },
  { id: 233, score: 28 },
  { id: 231, score: 33 },
];

const calculateHighestAverage = (marks = [], num = 1) => {
  // 1단계: 학생 ID별로 점수를 그룹화합니다.
  const grouped = {};
  for (const { id, score } of marks) {
    if (grouped.hasOwnProperty(id)) {
      grouped[id].push(score);
    } else {
      grouped[id] = [score];
    }
  }

  // 2단계: 상위 num개 점수의 평균을 계산하는 헬퍼 함수
  const findHighestAverage = (arr = [], upto = 1) => {
    const topScores = [...arr]
      .sort((a, b) => b - a)
      .slice(0, upto);
    return (
      topScores.reduce((acc, val) => acc + val, 0) / topScores.length
    );
  };

  // 3단계: 각 학생의 평균을 계산해 결과 객체를 완성합니다.
  const res = {};
  for (const id in grouped) {
    res[id] = findHighestAverage(grouped[id], num);
  }
  return res;
};

console.log(calculateHighestAverage(marks, 5));
console.log(calculateHighestAverage(marks, 4));
console.log(calculateHighestAverage(marks));

실행 결과

콘솔에 출력되는 결과는 다음과 같습니다.

{ '231': 38.6, '233': 40 }
{ '231': 39.75, '233': 40.5 }
{ '231': 44, '233': 42 }

세 번째 호출처럼 num을 생략하면 기본값 1이 적용되어, 각 학생의 최고 점수 하나만으로 평균이 계산됩니다. 즉, 그 학생의 역대 최고 점수가 그대로 결과값이 됩니다.

코드 설명

  • 점수 그룹화: 구조 분해 할당(const { id, score })으로 각 객체에서 필요한 값만 꺼내고, hasOwnProperty()로 해당 학생의 점수 배열이 이미 존재하는지 확인한 후 점수를 추가합니다.
  • 원본 데이터 보호: 정렬 전에 스프레드 연산자([...arr])로 복사본을 만들기 때문에 원본 배열이 변경되지 않습니다.
  • 안전한 평균 계산: reduce()에 초기값 0을 지정했기 때문에 빈 배열이 전달되더라도 오류 없이 처리됩니다.
  • 기록 부족 처리: slice(0, upto)는 배열 길이보다 큰 값이 들어와도 에러 없이 전체 요소를 반환하므로, 기록이 num개보다 적은 학생도 자동으로 올바르게 처리됩니다.