Go sort Package

Sort slices with a one-liner, implement custom orderings, keep equal elements stable, and binary-search sorted data.

sort.Slice sort.SliceStable sort.Ints / Strings sort.Interface sort.Search sort.IsSorted Reverse
โšก

Sorting Slices

โ„น๏ธ
sort.Slice is the everyday workhorse. Pass the slice and a less function that returns true when element i should come before element j. It uses an unstable sort โ€” equal elements may be reordered.
sort.Slice โ€” sort any slice with a comparator sort.Slice
nums := []int{5, 2, 8, 1, 9, 3}
sort.Slice(nums, func(i, j int) bool {
    return nums[i] < nums[j]   // ascending
})
// [1 2 3 5 8 9]

// Descending โ€” flip the comparison
sort.Slice(nums, func(i, j int) bool {
    return nums[i] > nums[j]
})
// [9 8 5 3 2 1]

words := []string{"banana", "apple", "cherry"}
sort.Slice(words, func(i, j int) bool {
    return words[i] < words[j]
})
// [apple banana cherry]
Sorting structs by a field Structs
type Person struct {
    Name string
    Age  int
}

people := []Person{
    {"Alice", 30},
    {"Bob", 25},
    {"Charlie", 35},
    {"Diana", 25},
}

// Sort by Age ascending
sort.Slice(people, func(i, j int) bool {
    return people[i].Age < people[j].Age
})
// [{Bob 25} {Diana 25} {Alice 30} {Charlie 35}]
// (Bob and Diana order is not guaranteed โ€” use SliceStable for that)

// Sort by Name alphabetically
sort.Slice(people, func(i, j int) bool {
    return people[i].Name < people[j].Name
})
// [{Alice 30} {Bob 25} {Charlie 35} {Diana 25}]
sort.SliceStable โ€” preserve order of equal elements Stable
// SliceStable guarantees that equal elements keep their original relative order
// Useful when sorting by one field but preserving a prior sort on another

// Step 1: sort by Name
sort.SliceStable(people, func(i, j int) bool {
    return people[i].Name < people[j].Name
})

// Step 2: sort by Age โ€” Name order is preserved within equal ages
sort.SliceStable(people, func(i, j int) bool {
    return people[i].Age < people[j].Age
})
// [{Bob 25} {Diana 25} {Alice 30} {Charlie 35}]
// Bob comes before Diana (alphabetical) because SliceStable preserved it
๐ŸŽฏ

Built-in Convenience Functions

๐Ÿ’ก
For the three most common types there are pre-built functions so you don't need to write a comparator. Each also has a corresponding AreSorted check and Search variant.
sort.Ints & sort.Strings Convenience
nums := []int{3, 1, 4, 1, 5, 9}
sort.Ints(nums)
// [1 1 3 4 5 9]

words := []string{"go", "rust", "c"}
sort.Strings(words)
// [c go rust]

floats := []float64{3.14, 1.41, 2.71}
sort.Float64s(floats)
// [1.41 2.71 3.14]
IntsAreSorted & StringsAreSorted Check
nums := []int{1, 2, 3, 5}
sort.IntsAreSorted(nums)    // true

unsorted := []int{3, 1, 2}
sort.IntsAreSorted(unsorted) // false

words := []string{"a", "b", "c"}
sort.StringsAreSorted(words) // true

// Generic version โ€” works with any less function
sort.SliceIsSorted(nums, func(i, j int) bool {
    return nums[i] < nums[j]
}) // true
๐Ÿ”‘

Multi-Key Sorting

Sorting by multiple fields in one pass Multi-Key
type Employee struct {
    Dept   string
    Name   string
    Salary int
}

employees := []Employee{
    {"Eng", "Zara", 90000},
    {"Eng", "Alice", 95000},
    {"HR", "Bob", 70000},
    {"Eng", "Alice", 88000},
}

// Primary: Dept asc  Secondary: Name asc  Tertiary: Salary desc
sort.Slice(employees, func(i, j int) bool {
    a, b := employees[i], employees[j]
    if a.Dept != b.Dept {
        return a.Dept < b.Dept
    }
    if a.Name != b.Name {
        return a.Name < b.Name
    }
    return a.Salary > b.Salary  // highest salary first within same name
})
// [{Eng Alice 95000} {Eng Alice 88000} {Eng Zara 90000} {HR Bob 70000}]
๐ŸŽญ

sort.Interface

โ„น๏ธ
Implement sort.Interface on your own type to use sort.Sort, sort.Stable, and sort.Reverse. This is the older, more verbose approach โ€” prefer sort.Slice for simple cases.
Implementing sort.Interface Interface
type ByLength []string

func (b ByLength) Len() int           { return len(b) }
func (b ByLength) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) }

words := ByLength{"peach", "kiwi", "pineapple", "fig"}
sort.Sort(words)
// [fig kiwi peach pineapple]

// Stable version โ€” preserves original order for equal lengths
sort.Stable(words)
sort.Reverse โ€” wrap any Interface to flip the order Reverse
// sort.Reverse wraps any sort.Interface to sort in reverse
words := ByLength{"peach", "kiwi", "pineapple", "fig"}
sort.Sort(sort.Reverse(words))
// [pineapple peach kiwi fig]

// Also works with the convenience types
nums := sort.IntSlice{3, 1, 4, 1, 5}
sort.Sort(sort.Reverse(nums))
// [5 4 3 1 1]

// For sort.Slice, just flip the less function instead
sort.Slice(nums, func(i, j int) bool { return nums[i] > nums[j] })
sort.IntSlice, sort.StringSlice โ€” ready-made Interface types Convenience Types
// sort.IntSlice, sort.StringSlice, sort.Float64Slice
// implement sort.Interface so you can use sort.Search on them

nums := sort.IntSlice{1, 3, 5, 7, 9}

// Search within a sorted IntSlice
i := nums.Search(5)   // 2 โ€” index of 5
i  = nums.Search(4)   // 2 โ€” insertion point for 4

// You can call Sort directly on the value
s := sort.StringSlice{"banana", "apple", "cherry"}
s.Sort()
// [apple banana cherry]
โš–๏ธ

sort vs. slices package

๐Ÿ’ก
Go 1.21 added the slices package with generic sorting functions. They're often more ergonomic for typed slices. Both packages coexist โ€” use whichever reads clearer in context.
sort package (pre-1.21 style) sort
nums := []int{3, 1, 4, 1, 5}

sort.Ints(nums)

sort.Slice(nums, func(i, j int) bool {
    return nums[i] < nums[j]
})

i := sort.SearchInts(nums, 4)
slices package (Go 1.21+, generic) Go 1.21+
nums := []int{3, 1, 4, 1, 5}

slices.Sort(nums)             // type-inferred

slices.SortFunc(nums, func(a, b int) int {
    return cmp.Compare(a, b) // returns -1/0/1
})

i, _ := slices.BinarySearch(nums, 4)
When to prefer slices.SortFunc Guidance
import (
    "cmp"
    "slices"
)

type Person struct{ Name string; Age int }

people := []Person{{"Alice", 30}, {"Bob", 25}, {"Carol", 30}}

// slices.SortFunc takes a cmp function (returns int) not a less function (returns bool)
// Use cmp.Compare for ordered types; chain with || 0 for multi-key
slices.SortFunc(people, func(a, b Person) int {
    if n := cmp.Compare(a.Age, b.Age); n != 0 {
        return n
    }
    return cmp.Compare(a.Name, b.Name)
})
// [{Bob 25} {Alice 30} {Carol 30}]
๐Ÿ“‹

Quick Reference

Function Signature (simplified) Description
sort.Slice(slice any, less func(i,j int) bool)Sort any slice in-place; unstable
sort.SliceStable(slice any, less func(i,j int) bool)Stable sort; preserves equal element order
sort.SliceIsSorted(slice any, less func) boolReport whether slice is sorted by less
sort.Ints(a []int)Sort int slice ascending
sort.Strings(a []string)Sort string slice ascending
sort.Float64s(a []float64)Sort float64 slice ascending
sort.IntsAreSorted(a []int) boolTrue if int slice is ascending
sort.StringsAreSorted(a []string) boolTrue if string slice is ascending
sort.Sort(data Interface)Sort any type implementing sort.Interface
sort.Stable(data Interface)Stable sort on sort.Interface
sort.Reverse(data Interface) InterfaceReturn reversed view of sort.Interface
sort.IsSorted(data Interface) boolTrue if data is in sorted order
sort.Search(n int, f func(int) bool) intBinary search: smallest i where f(i) is true
sort.SearchInts(a []int, x int) intBinary search for x in sorted int slice
sort.SearchStrings(a []string, x string) intBinary search for x in sorted string slice
sort.SearchFloat64s(a []float64, x float64) intBinary search for x in sorted float64 slice