Skip to content

Commit 9c06248

Browse files
committed
Improved average calculation
1 parent 7ee0c25 commit 9c06248

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

server/src/controllers/CohortsController.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Request, Response } from 'express';
22
import { TraineesRepository } from '../repositories';
3-
import { LearningStatus, Test, Trainee } from '../models';
3+
import { LearningStatus, calculateAverageTestScore, Trainee } from '../models';
44

55
interface Cohort {
66
cohort: number | null;
@@ -76,24 +76,10 @@ export class CohortsController implements CohortsControllerType {
7676
LearningStatus: trainee.educationInfo.learningStatus,
7777
JobPath: trainee.employmentInfo.jobPath,
7878
strikes: trainee.educationInfo.strikes.length,
79-
averageTestScore: this.calculateAverageTestScore(trainee.educationInfo.tests),
79+
averageTestScore: calculateAverageTestScore(trainee.educationInfo.tests),
8080
};
8181
}
8282

83-
private calculateAverageTestScore(tests: Test[]): number | null {
84-
// Filter out tests without scores
85-
const scores = tests.map((test) => test.score).filter((score) => score !== undefined);
86-
if (scores.length === 0) {
87-
return null;
88-
}
89-
90-
// Calculate average
91-
const sum = scores.reduce((acc, score) => {
92-
return acc + score;
93-
}, 0);
94-
return sum / scores.length;
95-
}
96-
9783
private compareTraineeInCohort(a: Trainee, b: Trainee) {
9884
const statusIndexA = Object.values(LearningStatus).indexOf(a.educationInfo.learningStatus);
9985
const statusIndexB = Object.values(LearningStatus).indexOf(b.educationInfo.learningStatus);

server/src/models/Test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export interface Test {
44
readonly id: string;
55
date: Date;
66
type: TestType;
7-
score?: number;
7+
score: number | null;
88
result: TestResult;
99
comments?: string;
1010
}
@@ -20,3 +20,36 @@ export const validateTest = (test: Test): void => {
2020
throw new Error(`Unknown test type [${Object.values(TestType)}]`);
2121
}
2222
};
23+
24+
// Calculate average of all test scores, taking only the highest score for each test type
25+
export const calculateAverageTestScore = (tests: Test[]): number | null => {
26+
// Group by test type
27+
const testTypes = Object.groupBy(tests, (test) => test.type);
28+
29+
// Select highest test for each type
30+
const scores = Object.values(testTypes)
31+
.map((testsWithTheSameType) => {
32+
return getTestWithMaxScore(testsWithTheSameType);
33+
})
34+
.map((test) => test?.score)
35+
.filter((score) => score !== null && score !== undefined);
36+
37+
// Filter out tests without scores
38+
if (scores.length === 0) {
39+
return null;
40+
}
41+
42+
// Calculate average
43+
const sum = scores.reduce((acc, score) => {
44+
return acc + score;
45+
}, 0);
46+
return sum / scores.length;
47+
};
48+
49+
// Helper function to get the best test (highest score) from a list of tests
50+
const getTestWithMaxScore = (tests: Test[]): Test | null => {
51+
const sortedByScore = tests
52+
.filter((test: Test) => test.score !== null)
53+
.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
54+
return sortedByScore[0] ?? null;
55+
};

server/src/repositories/TraineesRepository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class MongooseTraineesRepository implements TraineesRepository {
7171
'educationInfo.learningStatus',
7272
'educationInfo.strikes.id',
7373
'educationInfo.tests.score',
74+
'educationInfo.tests.type',
7475
'educationInfo.currentCohort',
7576
'employmentInfo.jobPath',
7677
])

0 commit comments

Comments
 (0)