Go

Compare sort.Slice, sort.SliceStable, sort.Sort (sort.Interface) and slices.SortFunc. Which are stable, and what are the performance differences?

Question 533MediumGo 1.22 to 1.25

Stable: sort.SliceStable, sort.Stable and slices.SortStableFunc. Not stable: sort.Slice, sort.Sort, slices.Sort and slices.SortFunc, which all use pdqsort since Go 1.19. Equal elements may be reordered.

  • sort.Sort makes an interface method call for every Less and Swap.
  • sort.Slice uses a reflection-based swapper plus an index-based less(i, j) closure. The closure must reference the same slice you pass in, and getting that wrong is a classic bug.
  • slices.SortFunc (Go 1.21+) is generic, so the compiler specializes it per type. It has no reflection and no interface dispatch, and it is usually the fastest choice. It takes a three-way cmp(a, b) int on the elements rather than on indices. slices.Sort for cmp.Ordered types is faster still. Since Go 1.22, sort.Ints and sort.Strings just call slices.Sort.
type Person struct {
	Name string
	Age  int
}

people := []Person{{"Cy", 30}, {"Al", 25}, {"Bo", 30}}

// Age descending, then Name ascending (cmp.Or is Go 1.22+)
slices.SortFunc(people, func(a, b Person) int {
	return cmp.Or(cmp.Compare(b.Age, a.Age), strings.Compare(a.Name, b.Name))
})
fmt.Println(people) // [{Bo 30} {Cy 30} {Al 25}]

// Keep the existing order among equal ages
slices.SortStableFunc(people, func(a, b Person) int {
	return cmp.Compare(a.Age, b.Age)
})

What the interviewer is looking for: you pick slices in new code and you know that stability matters when you sort by several keys in successive passes. The comparator must also be a strict weak ordering. An inconsistent less gives a garbage order but does not panic.

More on More Standard Library Essentials

All 16 More Standard Library Essentials questions