WeCodeAcademy

Step 5: The Go version

Go's version reads almost like pseudocode: strings.FieldsFunc splits on every non-letter, a map[string]int counts, and sort.Slice sorts a slice of small structs. There are no generics or ownership rules to think about here; the language aims at being easy to read and fast to compile.

ExampleGo
package main

import (
  "fmt"
  "sort"
  "strings"
  "unicode"
)

type entry struct {
  word  string
  count int
}

func countWords(text string) []entry {
  words := strings.FieldsFunc(strings.ToLower(text), func(r rune) bool {
    return !unicode.IsLetter(r)
  })
  counts := map[string]int{}
  for _, w := range words {
    counts[w]++
  }
  list := make([]entry, 0, len(counts))
  for w, c := range counts {
    list = append(list, entry{w, c})
  }
  sort.Slice(list, func(i, j int) bool {
    if list[i].count != list[j].count {
      return list[i].count > list[j].count
    }
    return list[i].word < list[j].word
  })
  return list
}

func main() {
  text := "The quick brown fox jumps over the lazy dog. The end!"
  for _, e := range countWords(text) {
    fmt.Printf("%-6s %d\n", e.word, e.count)
  }
}
Output
the    3
brown  1
dog    1
end    1
fox    1
jumps  1
lazy   1
over   1
quick  1

The map's counts[w]++ works even for a new word because a missing key reads as the zero value 0. All four programs print exactly the same lines.

Quick check

Why does counts[w]++ work for a word seen for the first time in Go?

Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.

Tip: use the left and right arrow keys to move between lessons.