🎓
Student Grading Problem Solution
This is a solution to the https://github.com/one2nc/student-grading-go
Code
package main import ( "encoding/csv" "errors" "log" "os" "strconv" ) type Grade string const ( A Grade = "A" B Grade = "B" C Grade = "C" F Grade = "F" ) type student struct { firstName, lastName, university string test1Score, test2Score, test3Score, test4Score int } type studentStat struct { student finalScore float32 grade Grade } func parseCSV(filePath string) []student { var students []student f, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer f.Close() csvReader := csv.NewReader(f) data, err := csvReader.ReadAll() if err != nil { log.Fatal(err) } for i, row := range data { if i > 0 { // omit header line st, err := createStudentFromRow(row) if err != nil { log.Fatal(err) } students = append(students, st) } } return students } func createStudentFromRow(row []string) (student, error) { var st student if len(row) != 7 { return student{}, errors.New("invalid csv row") } st.firstName = row[0] st.lastName = row[1] st.university = row[2] t1Score, errT1 := strconv.Atoi(row[3]) t2Score, errT2 := strconv.Atoi(row[4]) t3Score, errT3 := strconv.Atoi(row[5]) t4Score, errT4 := strconv.Atoi(row[6]) if errT1 != nil || errT2 != nil || errT3 != nil || errT4 != nil { return student{}, errors.New("invalid csv row") } st.test1Score = t1Score st.test2Score = t2Score st.test3Score = t3Score st.test4Score = t4Score return st, nil } func calculateGrade(students []student) []studentStat { var studentStats []studentStat for _, st := range students { var ss studentStat avg := float32(st.test1Score+st.test2Score+st.test3Score+st.test4Score) / 4 ss.student = st ss.finalScore = avg ss.grade = getGrade(avg) studentStats = append(studentStats, ss) } return studentStats } func getGrade(score float32) Grade { if score >= 70 { return A } else if score < 70 && score >= 50 { return B } else if score < 50 && score >= 35 { return C } else { return F } } // EdgeCase - There could be multiple students with same finalScore func findOverallTopper(gradedStudents []studentStat) studentStat { maxScore := float32(0) var topper studentStat for _, s := range gradedStudents { if s.finalScore > maxScore { maxScore = s.finalScore topper = s } } return topper } // EdgeCase - There could be multiple students with same finalScore per university func findTopperPerUniversity(gs []studentStat) map[string]studentStat { topperPerUni := make(map[string]studentStat) studentsUniMap := createStudentUniMap(gs) for uni, students := range studentsUniMap { t := findOverallTopper(students) topperPerUni[uni] = t } return topperPerUni } func createStudentUniMap(gs []studentStat) map[string][]studentStat { studentsUniMap := make(map[string][]studentStat) for _, stStat := range gs { studentsUniMap[stStat.university] = append(studentsUniMap[stStat.university], stStat) } return studentsUniMap
Code
package main import ( "encoding/csv" "errors" "log" "os" "strconv" ) type Grade string const ( A Grade = "A" B Grade = "B" C Grade = "C" F Grade = "F" ) type student struct { firstName, lastName, university string test1Score, test2Score, test3Score, test4Score int } type studentStat struct { student finalScore float32 grade Grade } func parseCSV(filePath string) []student { var students []student f, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer f.Close() csvReader := csv.NewReader(f) data, err := csvReader.ReadAll() if err != nil { log.Fatal(err) } for i, row := range data { if i > 0 { // omit header line st, err := createStudentFromRow(row) if err != nil { log.Fatal(err) } students = append(students, st) } } return students } func createStudentFromRow(row []string) (student, error) { var st student if len(row) != 7 { return student{}, errors.New("invalid csv row") } st.firstName = row[0] st.lastName = row[1] st.university = row[2] t1Score, errT1 := strconv.Atoi(row[3]) t2Score, errT2 := strconv.Atoi(row[4]) t3Score, errT3 := strconv.Atoi(row[5]) t4Score, errT4 := strconv.Atoi(row[6]) if errT1 != nil || errT2 != nil || errT3 != nil || errT4 != nil { return student{}, errors.New("invalid csv row") } st.test1Score = t1Score st.test2Score = t2Score st.test3Score = t3Score st.test4Score = t4Score return st, nil } func calculateGrade(students []student) []studentStat { var studentStats []studentStat for _, st := range students { var ss studentStat avg := float32(st.test1Score+st.test2Score+st.test3Score+st.test4Score) / 4 ss.student = st ss.finalScore = avg ss.grade = getGrade(avg) studentStats = append(studentStats, ss) } return studentStats } func getGrade(score float32) Grade { if score >= 70 { return A } else if score < 70 && score >= 50 { return B } else if score < 50 && score >= 35 { return C } else { return F } } // EdgeCase - There could be multiple students with same finalScore func findOverallTopper(gradedStudents []studentStat) studentStat { maxScore := float32(0) var topper studentStat for _, s := range gradedStudents { if s.finalScore > maxScore { maxScore = s.finalScore topper = s } } return topper } // EdgeCase - There could be multiple students with same finalScore per university func findTopperPerUniversity(gs []studentStat) map[string]studentStat { topperPerUni := make(map[string]studentStat) studentsUniMap := createStudentUniMap(gs) for uni, students := range studentsUniMap { t := findOverallTopper(students) topperPerUni[uni] = t } return topperPerUni } func createStudentUniMap(gs []studentStat) map[string][]studentStat { studentsUniMap := make(map[string][]studentStat) for _, stStat := range gs { studentsUniMap[stStat.university] = append(studentsUniMap[stStat.university], stStat) } return studentsUniMap
Code
package main import ( "encoding/csv" "errors" "log" "os" "strconv" ) type Grade string const ( A Grade = "A" B Grade = "B" C Grade = "C" F Grade = "F" ) type student struct { firstName, lastName, university string test1Score, test2Score, test3Score, test4Score int } type studentStat struct { student finalScore float32 grade Grade } func parseCSV(filePath string) []student { var students []student f, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer f.Close() csvReader := csv.NewReader(f) data, err := csvReader.ReadAll() if err != nil { log.Fatal(err) } for i, row := range data { if i > 0 { // omit header line st, err := createStudentFromRow(row) if err != nil { log.Fatal(err) } students = append(students, st) } } return students } func createStudentFromRow(row []string) (student, error) { var st student if len(row) != 7 { return student{}, errors.New("invalid csv row") } st.firstName = row[0] st.lastName = row[1] st.university = row[2] t1Score, errT1 := strconv.Atoi(row[3]) t2Score, errT2 := strconv.Atoi(row[4]) t3Score, errT3 := strconv.Atoi(row[5]) t4Score, errT4 := strconv.Atoi(row[6]) if errT1 != nil || errT2 != nil || errT3 != nil || errT4 != nil { return student{}, errors.New("invalid csv row") } st.test1Score = t1Score st.test2Score = t2Score st.test3Score = t3Score st.test4Score = t4Score return st, nil } func calculateGrade(students []student) []studentStat { var studentStats []studentStat for _, st := range students { var ss studentStat avg := float32(st.test1Score+st.test2Score+st.test3Score+st.test4Score) / 4 ss.student = st ss.finalScore = avg ss.grade = getGrade(avg) studentStats = append(studentStats, ss) } return studentStats } func getGrade(score float32) Grade { if score >= 70 { return A } else if score < 70 && score >= 50 { return B } else if score < 50 && score >= 35 { return C } else { return F } } // EdgeCase - There could be multiple students with same finalScore func findOverallTopper(gradedStudents []studentStat) studentStat { maxScore := float32(0) var topper studentStat for _, s := range gradedStudents { if s.finalScore > maxScore { maxScore = s.finalScore topper = s } } return topper } // EdgeCase - There could be multiple students with same finalScore per university func findTopperPerUniversity(gs []studentStat) map[string]studentStat { topperPerUni := make(map[string]studentStat) studentsUniMap := createStudentUniMap(gs) for uni, students := range studentsUniMap { t := findOverallTopper(students) topperPerUni[uni] = t } return topperPerUni } func createStudentUniMap(gs []studentStat) map[string][]studentStat { studentsUniMap := make(map[string][]studentStat) for _, stStat := range gs { studentsUniMap[stStat.university] = append(studentsUniMap[stStat.university], stStat) } return studentsUniMap
Code
package main import ( "encoding/csv" "errors" "log" "os" "strconv" ) type Grade string const ( A Grade = "A" B Grade = "B" C Grade = "C" F Grade = "F" ) type student struct { firstName, lastName, university string test1Score, test2Score, test3Score, test4Score int } type studentStat struct { student finalScore float32 grade Grade } func parseCSV(filePath string) []student { var students []student f, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer f.Close() csvReader := csv.NewReader(f) data, err := csvReader.ReadAll() if err != nil { log.Fatal(err) } for i, row := range data { if i > 0 { // omit header line st, err := createStudentFromRow(row) if err != nil { log.Fatal(err) } students = append(students, st) } } return students } func createStudentFromRow(row []string) (student, error) { var st student if len(row) != 7 { return student{}, errors.New("invalid csv row") } st.firstName = row[0] st.lastName = row[1] st.university = row[2] t1Score, errT1 := strconv.Atoi(row[3]) t2Score, errT2 := strconv.Atoi(row[4]) t3Score, errT3 := strconv.Atoi(row[5]) t4Score, errT4 := strconv.Atoi(row[6]) if errT1 != nil || errT2 != nil || errT3 != nil || errT4 != nil { return student{}, errors.New("invalid csv row") } st.test1Score = t1Score st.test2Score = t2Score st.test3Score = t3Score st.test4Score = t4Score return st, nil } func calculateGrade(students []student) []studentStat { var studentStats []studentStat for _, st := range students { var ss studentStat avg := float32(st.test1Score+st.test2Score+st.test3Score+st.test4Score) / 4 ss.student = st ss.finalScore = avg ss.grade = getGrade(avg) studentStats = append(studentStats, ss) } return studentStats } func getGrade(score float32) Grade { if score >= 70 { return A } else if score < 70 && score >= 50 { return B } else if score < 50 && score >= 35 { return C } else { return F } } // EdgeCase - There could be multiple students with same finalScore func findOverallTopper(gradedStudents []studentStat) studentStat { maxScore := float32(0) var topper studentStat for _, s := range gradedStudents { if s.finalScore > maxScore { maxScore = s.finalScore topper = s } } return topper } // EdgeCase - There could be multiple students with same finalScore per university func findTopperPerUniversity(gs []studentStat) map[string]studentStat { topperPerUni := make(map[string]studentStat) studentsUniMap := createStudentUniMap(gs) for uni, students := range studentsUniMap { t := findOverallTopper(students) topperPerUni[uni] = t } return topperPerUni } func createStudentUniMap(gs []studentStat) map[string][]studentStat { studentsUniMap := make(map[string][]studentStat) for _, stStat := range gs { studentsUniMap[stStat.university] = append(studentsUniMap[stStat.university], stStat) } return studentsUniMap