Solution: Refactor collection processing

fun List<StudentGrades>.getBestForScholarship( semester: String ): List<StudentGrades> = this .filter { s -> s.grades .filter { it.semester == semester && it.passing } .sumOf { it.ects } > 30 } .sortedByDescending { averageGradeFromSemester(it, semester) } .take(10) fun averageGradeFromSemester( student: StudentGrades, semester: String ): Double = student.grades .filter { it.semester == semester } .map { it.grade } .average()

Example solution in playground

import org.junit.Test import java.util.Collections import kotlin.random.Random import kotlin.test.assertEquals fun List<StudentGrades>.getBestForScholarship( semester: String ): List<StudentGrades> = this .filter { s -> s.grades .filter { it.semester == semester && it.passing } .sumOf { it.ects } > 30 } .sortedByDescending { averageGradeFromSemester(it, semester) } .take(10) fun averageGradeFromSemester( student: StudentGrades, semester: String ): Double = student.grades .filter { it.semester == semester } .map { it.grade } .average() data class Grade( val passing: Boolean, var ects: Int, var semester: String, var grade: Double ) data class StudentGrades( val studentId: String, val grades: List<Grade> ) class StudentGradesIntenshipTest { @Test fun `should return best students for scholarship`() { val r = Random(123456789) val grades = List(100) { StudentGrades( "S$it", List(100) { Grade( passing = r.nextBoolean(), ects = r.nextInt(5) + 1, semester = "Semester ${r.nextInt(5)}", grade = r.nextDouble() * 5 + 2.0 ) } ) } val res1 = grades.getBestForScholarship("Semester 0") assertEquals( listOf("S83", "S47", "S26", "S53", "S4", "S29", "S50", "S34", "S44", "S59"), res1.map { it.studentId }, ) assertEquals( listOf("S30", "S66", "S49", "S14", "S6", "S12", "S25", "S99", "S7", "S40"), grades.getBestForScholarship("Semester 1").map { it.studentId } ) } @Test fun `should return empty list if no students passed`() { val grades = listOf( StudentGrades( "S1", listOf( Grade(false, 5, "Semester 0", 3.0), Grade(false, 5, "Semester 1", 3.0), Grade(false, 5, "Semester 2", 3.0), Grade(false, 5, "Semester 3", 3.0), Grade(false, 5, "Semester 4", 3.0), ) ), StudentGrades( "S2", listOf( Grade(false, 5, "Semester 0", 3.0), Grade(false, 5, "Semester 1", 3.0), Grade(false, 5, "Semester 2", 3.0), Grade(false, 5, "Semester 3", 3.0), Grade(false, 5, "Semester 4", 3.0), ) ), StudentGrades( "S3", listOf( Grade(false, 5, "Semester 0", 3.0), Grade(false, 5, "Semester 1", 3.0), Grade(false, 5, "Semester 2", 3.0), Grade(false, 5, "Semester 3", 3.0), Grade(false, 5, "Semester 4", 3.0), ) ), ) assertEquals( emptyList<String>(), grades.getBestForScholarship("Semester 0").map { it.studentId } ) } @Test fun `should sort by average grade for semester`() { val grades = listOf( StudentGrades( "S1", listOf( Grade(true, 25, "Semester 1", 3.0), Grade(true, 25, "Semester 1", 3.0), ) ), StudentGrades( "S2", listOf( Grade(true, 50, "Semester 1", 4.0), Grade(true, 50, "Semester 2", 1.0), Grade(true, 50, "Semester 3", 1.0), Grade(true, 50, "Semester 4", 1.0), ) ), StudentGrades("S3", listOf(Grade(true, 50, "Semester 1", 5.0),)), ) assertEquals( listOf("S3", "S2", "S1"), grades.getBestForScholarship("Semester 1").map { it.studentId } ) } @Test fun `should return 10 best students`() { val grades = List(100) { StudentGrades( "S$it", listOf( Grade( passing = true, ects = 50, semester = "Semester 0", grade = 5.0 + (0.01 * it) ) ) ) } assertEquals( List(10) { "S${99 - it}" }, grades.getBestForScholarship("Semester 0").map { it.studentId } ) } @Test fun `should calculate average grade from semester`() { assertEquals( 3.0, averageGradeFromSemester(StudentGrades( "S1", listOf( Grade(true, 25, "Semester 1", 3.0), Grade(true, 25, "Semester 1", 3.0), ) ), "Semester 1") ) assertEquals( 3.0, averageGradeFromSemester(StudentGrades( "S1", listOf( Grade(true, 10, "Semester 1", 2.0), Grade(true, 20, "Semester 1", 4.0), ) ), "Semester 1") ) assertEquals( 2.0, averageGradeFromSemester(StudentGrades( "S1", listOf( Grade(true, 10, "Semester 1", 2.0), Grade(true, 20, "Semester 2", 4.0), ) ), "Semester 1") ) } }