Word counter in Go

Count how many times each word appears in a text using strings and a map, then compare your program with a complete tested Go solution.

Level
Medium
Estimated time
20 min
Concepts covered
strings, maps

Counting words is the classic first use of a map: the word is the key and the number of occurrences is the value. Along the way you will meet the strings package and the map’s convenient zero value.

Statement

Write a function countWords(text string) map[string]int that returns how many times each word appears in text. Split the text on whitespace and compare words case-insensitively.

Constraints:

  • The signature must be func countWords(text string) map[string]int.
  • Split on any run of whitespace, ignoring extra spaces.
  • Treat Go, go and GO as the same word (lower case them).

Example

For the text "the cat sat on the mat", the counts are:

cat: 1
mat: 1
on: 1
sat: 1
the: 2

Map iteration order is random in Go, so the lines above are shown sorted for readability.

Starter code

package main

import (
	"fmt"
	"strings"
)

// countWords returns how many times each word appears in text.
func countWords(text string) map[string]int {
	counts := make(map[string]int)
	// Split text into words and count them.
	return counts
}

func main() {
	counts := countWords("the cat sat on the mat")
	fmt.Println(counts)
}

Hints

Hint 1

strings.Fields splits on any run of whitespace and drops empty pieces, which is exactly what you want here.

Hint 2

strings.ToLower(text) before splitting makes the count case-insensitive.

Hint 3

counts[word]++ works even the first time you see a word: reading a missing key returns the zero value 0, and ++ turns it into 1.

Solution

Show the solution
package main

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

func countWords(text string) map[string]int {
	counts := make(map[string]int)
	for _, word := range strings.Fields(strings.ToLower(text)) {
		counts[word]++
	}
	return counts
}

func main() {
	counts := countWords("the cat sat on the mat")

	words := make([]string, 0, len(counts))
	for word := range counts {
		words = append(words, word)
	}
	sort.Strings(words)

	for _, word := range words {
		fmt.Printf("%s: %d\n", word, counts[word])
	}
}

strings.ToLower normalises the case so The and the count together. strings.Fields splits the text on whitespace and skips empty entries, so extra spaces cause no trouble. The map starts empty, and counts[word]++ relies on the fact that a missing key reads back as 0, so the first sighting becomes 1 and every repeat adds one. Because a map has no guaranteed order, main sorts the keys before printing.

Common mistakes:

  • Using strings.Split(text, " "), which keeps empty strings when there are double spaces. strings.Fields avoids that.
  • Forgetting to lower-case, so Go and go are counted as different words.
  • Assuming a fixed print order. Map iteration order is randomised on purpose; sort the keys if order matters.

Maps are the key data structure here. Learn them thoroughly in Maps in Go.

Search

Search runs entirely in your browser.