From 366d79482f4bb1cb9d93e8dbf620c83821870b63 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Fri, 11 Nov 2016 16:47:38 +0100 Subject: Add Grade School --- go/grade-school/README.md | 53 +++++++++++ go/grade-school/grade_school_test.go | 173 +++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 go/grade-school/README.md create mode 100644 go/grade-school/grade_school_test.go diff --git a/go/grade-school/README.md b/go/grade-school/README.md new file mode 100644 index 0000000..5e7ad69 --- /dev/null +++ b/go/grade-school/README.md @@ -0,0 +1,53 @@ +# Grade School + +Write a small archiving program that stores students' names along with the grade that they are in. + +In the end, you should be able to: + +- Add a student's name to the roster for a grade + - "Add Jim to grade 2." + - "OK." +- Get a list of all students enrolled in a grade + - "Which students are in grade 2?" + - "We've only got Jim just now." +- Get a sorted list of all students in all grades. Grades should sort + as 1, 2, 3, etc., and students within a grade should be sorted + alphabetically by name. + - "Who all is enrolled in school right now?" + - "Grade 1: Anna, Barb, and Charlie. Grade 2: Alex, Peter, and Zoe. + Grade 3…" + +Note that all our students only have one name. (It's a small town, what +do you want?) + + +## For bonus points + +Did you get the tests passing and the code clean? If you want to, these +are some additional things you could try: + +- If you're working in a language with mutable data structures and your + implementation allows outside code to mutate the school's internal DB + directly, see if you can prevent this. Feel free to introduce additional + tests. + +Then please share your thoughts in a comment on the submission. Did this +experiment make the code better? Worse? Did you learn anything from it? + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +A pairing session with Phil Battos at gSchool [http://gschool.it](http://gschool.it) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/grade-school/grade_school_test.go b/go/grade-school/grade_school_test.go new file mode 100644 index 0000000..a827baf --- /dev/null +++ b/go/grade-school/grade_school_test.go @@ -0,0 +1,173 @@ +// API: +// +// type Grade struct { +// int, []string +// } +// +// type School +// func New() *School +// func (s *School) Add(string, int) +// func (s *School) Grade(int) []string +// func (s *School) Enrollment() []Grade + +package school + +import ( + "fmt" + "math/rand" + "strconv" + "testing" +) + +func TestNewSchoolIsEmpty(t *testing.T) { + if len(New().Enrollment()) != 0 { + t.Error("New school not empty") + } +} + +func list(e []Grade) (s string) { + for _, l := range e { + s += fmt.Sprintln(l) + } + return s +} + +func TestAddStudent(t *testing.T) { + exp := list([]Grade{{2, []string{"Aimee"}}}) + s := New() + s.Add("Aimee", 2) + got := list(s.Enrollment()) + if got != exp { + t.Errorf(`Add Aimee level 2, got +%sexpected: +%s`, got, exp) + } +} + +func TestAddMoreSameGrade(t *testing.T) { + exp := list([]Grade{{2, []string{"Blair James Paul"}}}) + s := New() + s.Add("Blair", 2) + s.Add("James", 2) + s.Add("Paul", 2) + got := list(s.Enrollment()) + if got != exp { + t.Errorf(`Add more same grade, got +%sexpected: +%s`, got, exp) + } +} + +func TestAddDifferentGrades(t *testing.T) { + exp := list([]Grade{ + {3, []string{"Chelsea"}}, + {7, []string{"Logan"}}, + }) + s := New() + s.Add("Chelsea", 3) + s.Add("Logan", 7) + got := list(s.Enrollment()) + if got != exp { + t.Errorf(`Add different grades, got +%sexpected: +%s`, got, exp) + } +} + +func TestGetGrade(t *testing.T) { + exp := []string{"Bradley", "Franklin"} + s := New() + s.Add("Bradley", 5) + s.Add("Franklin", 5) + s.Add("Jeff", 1) + got := s.Grade(5) + if len(got) == len(exp) { + if got[0] == exp[0] && got[1] == exp[1] || + got[0] == exp[1] && got[1] == exp[0] { // accept out of order + return + } + } + t.Errorf(`Get grade, got +%v +expected +%v`, got, exp) +} + +func TestNonExistantGrade(t *testing.T) { + s := New() + got := s.Grade(1) + if len(got) != 0 { + t.Errorf(`Get non-existant grade, got +%v +expected +[]`, got) + } +} + +func TestSortedEnrollment(t *testing.T) { + exp := list([]Grade{ + {3, []string{"Kyle"}}, + {4, []string{"Christopher Jennifer"}}, + {6, []string{"Kareem"}}, + }) + s := New() + s.Add("Jennifer", 4) + s.Add("Kareem", 6) + s.Add("Christopher", 4) + s.Add("Kyle", 3) + got := list(s.Enrollment()) + if got != exp { + t.Errorf(`Sorted enrollment, got +%sexpected: +%s`, got, exp) + } +} + +const ( + minLevel = 1 + maxLevel = 9 + enrollment = 400 +) + +func BenchmarkAddStudents(b *testing.B) { + const pool = 1e6 // pool of students + names := make([]string, pool) + levels := make([]int, pool) + for i := range names { + names[i] = strconv.Itoa(rand.Intn(1e5)) + levels[i] = minLevel + rand.Intn(maxLevel-minLevel+1) + } + p := 0 + b.ResetTimer() + for i := 0; i < b.N; i++ { + // bench combined time to create a school and add + // a number of students, drawn from a pool of students + s := New() + for t := 0; t < enrollment; t++ { + s.Add(names[p], levels[p]) + p = (p + 1) % pool + } + } +} + +func BenchmarkEnrollment(b *testing.B) { + const pool = 1000 // pool of schools + ss := make([]*School, pool) + for i := range ss { + s := New() + for t := 0; t < enrollment; t++ { + s.Add( + strconv.Itoa(rand.Intn(1e5)), + minLevel+rand.Intn(maxLevel-minLevel+1)) + } + ss[i] = s + } + p := 0 + b.ResetTimer() + for i := 0; i < b.N; i++ { + // bench time to get enrollment of a full school, + // averaged over a pool of schools. + ss[p].Enrollment() + p = (p + 1) % pool + } +} -- cgit v1.2.3