Menu

Golang Sort Slice: slices.Sort, SortFunc and Multiple Fields

Sort slices in Go with slices.Sort and slices.SortFunc, sort structs by one or several fields with cmp.Compare, keep equal elements in order with a stable sort, and read older sort.Slice code.

This page includes runnable editors - edit, run, and see output instantly.

Sorting built-in types

slices.Sort sorts any slice whose element type is ordered: integers, floats and strings. It sorts in place and returns nothing.

Output:

[3 7 19 42 88]
[Bob Carl alice lisa]
true
2 true

Strings sort by bytes, so every uppercase ASCII letter comes before every lowercase one. That is rarely what a user expects for names. The next section fixes it.

The slices package arrived in Go 1.21. Its Sort is a pattern-defeating quicksort: O(n log n), in place, and not stable.

Custom order with SortFunc

slices.SortFunc takes a comparison function func(a, b T) int. Return a negative number when a should come first, a positive number when b should, and zero when they are equal. The cmp.Compare helper returns exactly that for ordered types.

strings.ToLower inside a comparison allocates a new string whenever its input has an uppercase letter, and the comparison runs about n log n times. For big slices, compute the lowercase keys once. For names in other languages (accents, locale rules), use golang.org/x/text/collate, which is outside the standard library.

A comparison function must be consistent: if it says a comes before b, it must say b comes after a. One that breaks this (for example, returning -1 whenever two values differ) produces a wrongly ordered slice with no error. Subtracting integers (return a - b) looks neat but overflows for large values; use cmp.Compare.

Sorting structs

The comparison function receives elements, so sorting structs by a field is the same call:

Employees with equal salaries may come out in any order here, because SortFunc is not stable. If you need a guaranteed order, either break ties with more fields or use a stable sort.

Sorting by multiple fields

Compare the most important field first and move to the next only on a tie. cmp.Or (Go 1.22) returns its first non-zero argument, which turns this into one line:

Output:

eng     150 Cy
eng     120 Ana
eng     120 Eve
sales    90 Bob
sales    90 Dee

Every comparison is evaluated even when the first one decides, since they are plain arguments. That costs little for field comparisons. When a tie-breaker is expensive, write the if c := ...; c != 0 { return c } chain by hand.

Stable sort

A stable sort keeps elements that compare equal in their original order. That matters when the input already has a meaningful order, for example records sorted by time that you now group by user.

This prints [{ana 2} {ana 4} {bob 1} {bob 3} {bob 5}]: within each user, the original sequence survives. Stable sorting does more work, so use it only when the order of equal elements matters.

Sorting a map

Maps have no order. To show a map sorted by key, sort its keys: slices.Sorted(maps.Keys(m)) (Go 1.23). To sort by value, sort the keys with a comparison that looks up the values:

The tie-breaker on the word matters: without it, chan and slice (both 7) would print in a different order from run to run, because the keys come out of the map in random order. See maps for more.

The sort package: sort.Slice and friends

Before Go 1.21, sorting went through the sort package. You will see it in a lot of existing code:

sort.Ints(nums)
sort.Strings(names)
sort.Slice(staff, func(i, j int) bool {
	return staff[i].Salary < staff[j].Salary
})
sort.SliceStable(staff, func(i, j int) bool { ... })

Differences worth knowing:

sort.Sliceslices.SortFunc
Function receivesindexes i, jelements a, b
Returnsbool (is i less than j)int (negative, zero, positive)
Type safetytakes any, uses reflectiongeneric, checked at compile time
Speedslowerfaster

A common sort.Slice bug is closing over a different slice than the one being sorted, since the less function indexes by position. SortFunc cannot have that bug because it hands you the elements.

The sort.Interface type (Len, Less, Swap) is the oldest form. It is still the way to sort data that is not a single slice, such as two parallel slices that must move together. Since Go 1.22, sort.Ints, sort.Strings and sort.Float64s simply call slices.Sort.

Common mistakes

  • Expecting Sort to return the sorted slice. It sorts in place and returns nothing. Use slices.Sorted(slices.Values(s)) if you want a new sorted slice, or slices.Clone first.
  • Assuming equal elements keep their order. Only the Stable variants promise that.
  • Subtracting to compare. a - b overflows. Use cmp.Compare.
  • Sorting floats with NaN. cmp.Compare orders NaN before every other value, which keeps the sort consistent. A hand-written a < b comparison does not.

Frequently Asked Questions

How do you sort a slice in Go?

For numbers and strings, call slices.Sort(s) (Go 1.21). It sorts in place in ascending order. For anything else, or a different order, use slices.SortFunc(s, func(a, b T) int { ... }), where the function returns a negative number if a comes first, positive if b does, and zero if they are equal.

How do I sort a slice in descending order in Go?

Swap the arguments in the comparison: slices.SortFunc(s, func(a, b int) int { return cmp.Compare(b, a) }). Or sort ascending and then call slices.Reverse(s).

How do I sort a slice of structs by multiple fields in Go?

Compare the first field, and fall through to the next only when it is equal. cmp.Or (Go 1.22) does exactly that: return cmp.Or(cmp.Compare(a.Dept, b.Dept), cmp.Compare(b.Salary, a.Salary), strings.Compare(a.Name, b.Name)) returns the first non-zero result.

What is the difference between sort.Slice and slices.SortFunc?

sort.Slice(s, func(i, j int) bool) is the older API: it takes a less function over indexes and uses reflection to swap elements. slices.SortFunc(s, func(a, b T) int) is generic, type-checked, takes the elements directly, and is faster. New code should use the slices package; sort.Slice is still common in code written before Go 1.21.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED