Problem overview
The function hasPassed receives a slice of integer grades and returns a bool: true if the student's average grade is 5 or more, false otherwise. The average is the sum of all grades divided by how many there are.
For [4, 7, 5, 9, 8, 2] the sum is 35 and there are 6 grades, so the average is about 5.83, which passes. For [4, 7, 5, 3, 8, 2] the sum is 29 and the average is about 4.83, which fails.
Approach
The task breaks into three small jobs: add up the grades, divide by the count, and compare the result with 5. The only repeated work is the addition, so only that part needs a loop. The loop visits every grade once and adds it to a running total.
The division deserves a second look. In Go, dividing two int values gives an int: the fractional part is dropped. So 35 / 6 is 5 and 29 / 6 is 4, not 5.83 and 4.83. That could look like a loss of accuracy, but here it is harmless. The pass mark is the whole number 5, and for non-negative sums the truncated average is at least 5 exactly when the real average is. A real average of 4.99 truncates to 4, which fails, just as it should.
Step by step
- Define the function. It takes
grades, a[]int, and returns abool. Go puts the return type after the parameter list. - Declare the running total.
sum := 0creates anintvariable. It must exist before the loop so it keeps its value from one pass to the next. - Loop over the grades with
for ... range. Each pass gives an index and a value. The index isn't needed, and Go refuses variables that are declared but never used, so it goes to the blank identifier_. - Add each grade to
suminside the loop. - Compute the average after the loop by dividing
sumbylen(grades). Both operands areint, so this is integer division. - Return the comparison.
average >= 5is already abool, so there is no need for anifthat returnstruein one branch andfalsein the other.
The solution in Go
func hasPassed(grades []int) bool {
sum := 0
for _, grade := range grades {
sum += grade
}
average := sum / len(grades)
return average >= 5
}
The Go details worth a closer look:
- Slices and
len.gradesis a slice, a view onto a sequence of ints. The built-inlenreturns its number of elements. - Integer division. Go divides two ints without converting to a floating-point number. If you want the exact average, convert first:
float64(sum) / float64(len(grades)). Mixing anintand afloat64in one expression does not compile, so the conversions are needed on both operands. - Division by zero. With an empty slice,
len(grades)is 0 and the division stops the program with a run-time panic,integer divide by zero. This solution assumes at least one grade; if empty input were possible, you would checklen(grades) == 0first and decide what the answer should be. :=declares,=assigns.sum := 0andaverage := ...declare new variables and infer their types. Inside the loop,sum += gradeupdates the existing variable.- Overflow. An
intis 64 bits here and silently wraps around if a sum gets too large. For grades this is not a concern.
Complexity
Time: O(n). The loop runs exactly once per grade, where n is the length of the slice. The division and the comparison take constant time.
Space: O(1). The function keeps only sum, average and the loop variable, however long the slice is.
Edge cases and common mistakes
- Exactly 5.
[5, 5, 5]has an average of exactly 5, so the result istrue. The comparison must be>=, not>. - Just below 5.
[5, 5, 4]has a real average of 4.67. The integer average is 4, so the result isfalse. - A single grade.
[9]gives an average of 9 andtrue;[3]givesfalse. - Dividing inside the loop. Dividing each grade before adding it truncates every grade separately, so the answer can be wrong. Divide once, after the loop.
- Forgetting that
lenis a function. Go slices have no.lengthor.size(); uselen(grades).
Testing
[]int{4, 7, 5, 9, 8, 2}givestrue.[]int{4, 7, 5, 3, 8, 2}givesfalse.[]int{5, 5, 4, 6}givestrue.[]int{9}givestrue.