ZetCode

Golang slices.Sort

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 slices.Sort 函数。我们将通过不同数据类型的实际示例涵盖排序操作。

slices.Sort 函数按升序对切片元素进行排序。它是 Go 实验性 slices 包的一部分,可与有序类型一起使用。

此函数针对性能进行了优化,并提供了一种便捷的方法来排序集合,而无需为基本情况编写自定义排序逻辑。

基本 slices.Sort 示例

slices.Sort 最简单的用法是按升序对整数切片进行排序。该函数会就地修改原始切片。

basic_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{5, 2, 9, 1, 5, 6}
    slices.Sort(numbers)
    fmt.Println("Sorted numbers:", numbers)
}

我们创建一个无序数字的切片并对它们进行排序。输出显示数字按升序排列。原始切片已被修改。

排序字符串

slices.Sort 可以按字母顺序对字符串切片进行排序。本示例演示了如何对姓名列表进行排序。

string_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    names := []string{"Zoe", "Alice", "Bob", "Charlie"}
    slices.Sort(names)
    fmt.Println("Sorted names:", names)
}

字符串按字典顺序排序。排序区分大小写,在 ASCII 顺序中大写字母排在小写字母之前。

使用自定义比较函数对结构体进行排序

对于自定义类型,我们使用 slices.SortFunc 和一个比较函数。本示例按年龄对人员进行排序。

struct_sort.go
package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 20},
    }
    
    slices.SortFunc(people, func(a, b Person) int {
        return cmp.Compare(a.Age, b.Age)
    })
    
    fmt.Println("People sorted by age:", people)
}

我们定义一个使用 cmp.Compare 来确定顺序的比较函数。该函数返回 -1、0 或 1,分别表示小于、等于或大于。

降序排序

要按降序排序,我们会反转比较逻辑。本示例按从高到低的顺序对数字进行排序。

descending_sort.go
package main

import (
    "cmp"
    "fmt"
    "slices"
)

func main() {
    numbers := []int{5, 2, 9, 1, 5, 6}
    
    slices.SortFunc(numbers, func(a, b int) int {
        return cmp.Compare(b, a) // Reverse order
    })
    
    fmt.Println("Descending order:", numbers)
}

通过比较 b 和 a 而不是 a 和 b,我们反转了排序顺序。对于任何可比较的类型,此技术都适用。

使用多重条件进行排序

复杂的排序可以使用多个字段。本示例按姓氏排序,然后按名字排序。

multi_field_sort.go
package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Person struct {
    First string
    Last  string
}

func main() {
    people := []Person{
        {"Alice", "Smith"},
        {"Bob", "Johnson"},
        {"Alice", "Johnson"},
    }
    
    slices.SortFunc(people, func(a, b Person) int {
        if c := cmp.Compare(a.Last, b.Last); c != 0 {
            return c
        }
        return cmp.Compare(a.First, b.First)
    })
    
    fmt.Println("Sorted people:", people)
}

比较首先检查姓氏,然后如果姓氏相同,则回退到名字。这会创建自然的排序顺序。

稳定排序

slices.SortStableFunc 维护相等元素的相对顺序。当保留原始顺序很重要时,这很有用。

stable_sort.go
package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Item struct {
    Name  string
    Order int // Original position
}

func main() {
    items := []Item{
        {"A", 1},
        {"B", 2},
        {"A", 3},
    }
    
    slices.SortStableFunc(items, func(a, b Item) int {
        return cmp.Compare(a.Name, b.Name)
    })
    
    fmt.Println("Stable sorted items:", items)
}

两个“A”项都保持了它们原始的相对顺序(1 在 3 之前)。常规排序可能不会为相等元素保留此排序。

性能注意事项

排序函数使用高效的算法。本示例对不同大小的切片进行排序进行基准测试。

performance.go
package main

import (
    "fmt"
    "math/rand"
    "slices"
    "time"
)

func main() {
    sizes := []int{100, 10_000, 1_000_000}
    
    for _, size := range sizes {
        slice := make([]int, size)
        for i := range slice {
            slice[i] = rand.Intn(size)
        }
        
        start := time.Now()
        slices.Sort(slice)
        elapsed := time.Since(start)
        
        fmt.Printf("Sorted %d elements in %v\n", size, elapsed)
    }
}

该实现对大多数情况使用优化的快速排序。对于最坏情况的输入,性能会下降到 O(n^2),尽管在实践中这种情况很少见。

来源

Go 实验性切片包文档

本教程通过在各种场景下对不同数据类型进行排序的实际示例,介绍了 Go 中的 slices.Sort 函数。

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程