22. Slices — Homework solutions
The .go solution files are in
exercises/22/homework/solutions/.
Problem 1 — Favourite games
Problem. Print a numbered list using
range.
How to think about it. range gives you
the position (starting at 0) and the value. Build each line from the
position plus 1, a dot, a space and the value.
Worked solution.
package main
import "fmt"
func main() {
games := []string{"Minecraft", "Terraria", "Stardew Valley", "Hades", "Tetris"}
for i, name := range games {
fmt.Printf("%d. %s\n", i+1, name)
}
}Output:
1. Minecraft
2. Terraria
3. Stardew Valley
4. Hades
5. Tetris
Common mistakes.
- Printing
iand getting0. Minecraft. Printi+1. - Using
for i := 0; i < len(games); i++and thengames[i]. That works, butrangeis more direct.
Problem 2 — Sum the slice
Problem. Add every number in a slice, and print the total.
How to think about it. The accumulate pattern from
Chapter 20: keep a running total, updated inside the loop. The position
is not needed, so it is _.
Worked solution.
package main
import "fmt"
func main() {
scores := []int{12, 7, 24, 9, 30}
total := 0
for _, score := range scores {
total += score
}
fmt.Println("Total:", total)
}Output:
Total: 82
Common mistakes.
- Forgetting
total := 0before the loop. Go stops withundefined: total.
Problem 3 — Insert and remove
Problem. Do four slice operations, printing the slice after each.
How to think about it. Write a small printing
function once, and call it after each step. Each operation is then one
line. The slice is passed in as an argument, and %-18s from
Chapter 14 lines up the labels.
Worked solution.
package main
import "fmt"
func show(label string, items []string) {
fmt.Printf("%-18s %v\n", label, items)
}
func main() {
items := []string{"apple", "banana", "cherry"}
show("Start", items)
items = append(items, "date")
show("After append", items)
items = append([]string{"apricot"}, items...)
show("After insert at 0", items)
items = items[:len(items)-1]
show("After remove last", items)
items = append(items[:1], items[2:]...)
show("After remove at 1", items)
}Output:
Start [apple banana cherry]
After append [apple banana cherry date]
After insert at 0 [apricot apple banana cherry date]
After remove last [apricot apple banana cherry]
After remove at 1 [apricot banana cherry]
Common mistakes.
- Writing
append(items, "date")on its own line. Go stops withappend(items, "date") (value of type []string) is not used. Assign the result back. - Writing
items[1] = ""instead of removing the position. That leaves an empty string in the slice. - Mixing up the positions in
append(items[:1], items[2:]...). The first part stops before position 1, and the second part starts after it.
Challenge — Reverse a slice
Problem. reverse returns a new slice,
and the original is unchanged.
How to think about it. Build a new slice inside the
function. Walk the original from last to first with a three-part
for, append each value to the new slice, and return it. An
empty slice needs no special case, because the loop body never runs.
Worked solution.
package main
import "fmt"
func reverse(items []string) []string {
result := []string{}
for i := len(items) - 1; i >= 0; i-- {
result = append(result, items[i])
}
return result
}
func main() {
fruits := []string{"apple", "banana", "cherry"}
fmt.Println(fruits) // [apple banana cherry]
backwards := reverse(fruits)
fmt.Println(backwards) // [cherry banana apple]
fmt.Println(fruits) // [apple banana cherry]
fmt.Println(reverse([]string{})) // []
}Chapter 24 shows slices.Reverse, which does this job in
the standard library. The loop above is for understanding how it
works.
Common mistakes.
- Changing
itemsdirectly instead of building a new slice. A function shares its caller's items, so the original changes too, and the problem says it must not:
func reverseWrong(items []string) []string {
for i := 0; i < len(items)/2; i++ {
last := len(items) - 1 - i
items[i], items[last] = items[last], items[i]
}
return items
}
func main() {
fruits := []string{"apple", "banana", "cherry"}
backwards := reverseWrong(fruits)
fmt.Println(backwards) // [cherry banana apple]
fmt.Println(fruits) // [cherry banana apple]
}- Starting the loop at
len(items). That position does not exist, and the program crashes withpanic: runtime error: index out of range [3] with length 3. Start atlen(items) - 1, and keep going whilei >= 0.
Done?
The next chapter teaches maps, which look up a value by a name instead of by a position.