A guide to sorting in Go

Programming languages often provide ready-made helpers for sorting collections due to the incredibly common nature of this task. Go is no different with its provision of the sort package for all your sorting needs.

Sorting data is one of the most common tasks you may find yourself performing ever so often. This article explores a few techniques in Go that should make the sorting of any data collection a breeze.

Sort a slice of strings

The sort.Strings method sorts a slice of strings in increasing order as shown below:

func main() {
	s := []string{"James", "John", "Peter", "Andrew", "Matthew", "Luke"}
	sort.Strings(s)
	fmt.Println(s) // [Andrew James John Luke Matthew Peter]
}

The sort.StringsAreSorted method also exists to help you check if a string slice is in its sorted form (that is, in increasing order):

func main() {
	s := []string{"James", "John", "Peter", "Andrew", "Matthew", "Luke"}
	fmt.Println(sort.StringsAreSorted(s)) // false
	sort.Strings(s)
	fmt.Println(sort.StringsAreSorted(s)) // true
}

Sort a slice of integers

To sort a slice of integers, use the sort.Ints method as shown below:

func main() {
	intSlice := []int{4, 5, 2, 1, 3, 9, 7, 8, 6}
	fmt.Println(sort.IntsAreSorted(intSlice)) // false
	sort.Ints(intSlice)
	fmt.Println(intSlice) // [1 2 3 4 5 6 7 8 9]
	fmt.Println(sort.IntsAreSorted(intSlice)) // true
}

Sort a slice of floats

A slice of float64s may be sorted in increasing order using sort.Float64s:

func main() {
	f := []float64{math.NaN(), -0.2, -1.3, 0.9, 4.8, 2.1}
	fmt.Println(sort.Float64sAreSorted(f)) // false
	sort.Float64s(f)
	fmt.Println(f) // [NaN -1.3 -0.2 0.9 2.1 4.8]
	fmt.Println(sort.Float64sAreSorted(f)) // true
}

Sort a slice of structs

To sort a slice of structs in Go, you need to use a less function along with either the sort.Slice or sort.SliceStable methods. Here’s how we can sort a slice of persons according to their names and ages for example:

type Person struct {
	name string
	age  int
}

func main() {
	{%raw %}people := []Person{{"Sally", 20}, {"David", 40}, {"Jon", 30}, {"Larry", 25}}{% endraw %}
	sort.SliceStable(people, func(i, j int) bool {
		return people[i].age < people[j].age
	})

	fmt.Println("Sorted by age:", people)

	sort.SliceStable(people, func(i, j int) bool {
		return people[i].name < people[j].name
	})

	fmt.Println("Sorted by name:", people)
}
Output
Sorted by age: [{Sally 20} {Larry 25} {Jon 30} {David 40}]
Sorted by name: [{David 40} {Jon 30} {Larry 25} {Sally 20}]

Returning true from the less function will cause the element at index i to be sorted to a lower position than index j (The element at index i will come first in the sorted slice). Otherwise, the element at index j will come first if false is returned.

The difference between sort.Slice and sort.SliceStable is that the latter will keep the original order of equal elements while the former may not.

Sort a struct slice using multiple keys

In the example below, a slice of Person structs is sorted by LastName, and then by FirstName so that if two people have the same LastName, they’ll be ordered according to their FirstName.

type Person struct {
	FirstName string
	LastName  string
}

func main() {
	people := []Person{
		{"Michael", "Jackson"},
		{"Janet", "Jackson"},
		{"Keanu", "Reeves"},
		{"Reverend", "King"},
		{"Jane", "Austen"},
	}

	sort.SliceStable(people, func(i, j int) bool {
		if people[i].LastName != people[j].LastName {
			return people[i].LastName < people[j].LastName
		}

		return people[i].FirstName < people[j].FirstName
	})

	fmt.Println(people)
}

Notice how Janet Jackson comes before Michael Jackson in the output.

Output
[{Jane Austen} {Janet Jackson} {Michael Jackson} {Reverend King} {Keanu Reeves}]

Sort a map by key or value

Maps are unordered collections in Go so there is no provision for sorting a map using the sort package. However, if you really need to sort a map, you can try the methods described below.

From Go 1.12, you can print the map and it’ll be sorted by keys:

func main() {
	m := map[string]int{
		"sally": 45,
		"john":  5,
		"marcy": 15,
		"duff":  10,
		"tom":   20,
	}

	fmt.Println(m) // map[duff:10 john:5 marcy:15 sally:45 tom:20]
}

If you intend to do more than just printing the map or if you want to sort by value instead, you should use the methods described in this article to guarantee the iterate order of the map.

Conclusion

Sorting collections of data is pretty straightforward in Go through the use of the sort package and the solutions presented above should suffice for the majority of situations you will face. If you know of a different way to sort that is not covered in this article, do share it in the comments section below.

Thanks for reading, and happy coding!