ZetCode

Golang slices.SortFunc

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 slices.SortFunc 函数。我们将通过实际示例涵盖切片的自定义排序。

slices.SortFunc 函数使用自定义比较函数对切片进行排序。它是 Go 实验性 slices 包的一部分。

当内置排序不满足需求时,此函数提供了灵活的排序。它允许您按照比较函数中定义的任何标准进行排序。

基本的 slices.SortFunc 示例

slices.SortFunc 最简单的用法是以降序对整数进行排序。我们定义一个比较函数,它颠倒了正常的顺序。

basic_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
    
    slices.SortFunc(numbers, func(a, b int) int {
        return b - a // For descending order
    })
    
    fmt.Println("Sorted numbers:", numbers)
}

当 a 应该排在 b 之后时,比较函数返回一个正数。这会导致整数切片按降序排序。

按长度对字符串进行排序

slices.SortFunc 可以按长度而不是字典顺序对字符串进行排序。此示例演示了如何实现自定义字符串排序。

string_length_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    words := []string{"apple", "banana", "kiwi", "orange"}
    
    slices.SortFunc(words, func(a, b string) int {
        return len(a) - len(b)
    })
    
    fmt.Println("Sorted by length:", words)
}

比较函数减去字符串长度以确定顺序。较短的字符串会出现在排序结果的前面。

按字段对结构体进行排序

我们可以使用 slices.SortFunc 按特定字段对结构体进行排序。此示例按年龄对人员进行排序。

struct_sort.go
package main

import (
    "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 a.Age - b.Age
    })
    
    fmt.Println("Sorted by age:", people)
}

比较函数访问每个结构体的 Age 字段。结果将从最年轻到最年长的人进行排序。

不区分大小写的字符串排序

此示例演示了使用 slices.SortFunc 对字符串进行不区分大小写的排序。

case_insensitive_sort.go
package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    words := []string{"Apple", "banana", "cherry", "apricot"}
    
    slices.SortFunc(words, func(a, b string) int {
        return strings.Compare(strings.ToLower(a), strings.ToLower(b))
    })
    
    fmt.Println("Case-insensitive sort:", words)
}

比较在比较之前将两个字符串都转换为小写。这确保了排序会忽略单词之间的区分大小写差异。

多字段排序

slices.SortFunc 可以实现复杂的排序标准。此示例按多个字段(姓氏,然后是名字)进行排序。

multi_field_sort.go
package main

import (
    "fmt"
    "slices"
    "strings"
)

type Person struct {
    First string
    Last  string
}

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

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

自定义顺序排序

此示例展示了如何根据自定义优先级顺序而不是自然顺序对元素进行排序。

custom_order_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    colors := []string{"red", "blue", "green", "red", "blue"}
    priority := map[string]int{"red": 1, "blue": 2, "green": 3}
    
    slices.SortFunc(colors, func(a, b string) int {
        return priority[a] - priority[b]
    })
    
    fmt.Println("Sorted by priority:", colors)
}

比较使用优先级映射来定义排序顺序。在排序结果中,红色排在前面,然后是蓝色,接着是绿色。

稳定排序

虽然 slices.SortFunc 默认不是稳定的,但我们可以通过在比较中包含原始索引来实现稳定性。

stable_sort.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    items := []struct {
        Value int
        Index int
    }{
        {3, 0}, {1, 1}, {2, 2}, {1, 3}, {3, 4},
    }
    
    slices.SortFunc(items, func(a, b struct {
        Value int
        Index int
    }) int {
        if a.Value != b.Value {
            return a.Value - b.Value
        }
        return a.Index - b.Index
    })
    
    fmt.Println("Stable sort result:", items)
}

当值相等时,比较会使用原始索引来维护顺序。这实现了 slices.SortFunc 的稳定排序行为。

来源

Go 实验性切片包文档

本教程通过针对各种数据类型和场景的自定义排序的实际示例,涵盖了 Go 中的 slices.SortFunc 函数。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面有十多年的经验。

列出所有 Go 教程