Golang slices.SortStableFunc
最后修改于 2025 年 4 月 20 日
本教程将介绍如何在 Go 中使用 slices.SortStableFunc 函数。我们将通过实际示例和自定义比较函数来讲解稳定排序。
slices.SortStableFunc 函数在排序切片时会保持相等元素的原始顺序。它是 Go 实验性 slices 包的一部分。
当您需要在排序后保持相等元素的相对顺序时,此函数非常有用。它接受一个自定义比较函数来进行排序。
基本的 SortStableFunc 示例
slices.SortStableFunc 最简单的用法是按升序对整数进行排序。我们定义一个返回 -1、0 或 1 的比较函数。
package main
import (
"fmt"
"slices"
)
func main() {
numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.SortStableFunc(numbers, func(a, b int) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
})
fmt.Println("Sorted numbers:", numbers)
}
我们对整数切片进行排序,同时保持相等元素的顺序。比较函数遵循标准的“小于”约定。
按长度对字符串进行排序
slices.SortStableFunc 可以根据自定义标准对字符串进行排序。此示例按长度对字符串进行排序,同时保持相同长度的原始顺序。
package main
import (
"fmt"
"slices"
)
func main() {
words := []string{"apple", "banana", "kiwi", "orange", "fig"}
slices.SortStableFunc(words, func(a, b string) int {
if len(a) < len(b) {
return -1
}
if len(a) > len(b) {
return 1
}
return 0
})
fmt.Println("Sorted by length:", words)
}
比较函数检查字符串长度而不是字典顺序。对于长度相等的字符串,将保留原始顺序。
按多个字段对结构体进行排序
我们可以将 slices.SortStableFunc 与自定义结构体类型一起使用。此示例按年龄对人员进行排序,对于年龄相同的人员,则按姓名排序。
package main
import (
"fmt"
"slices"
)
type Person struct {
Name string
Age int
}
func main() {
people := []Person{
{"Alice", 25},
{"Bob", 30},
{"Charlie", 25},
{"David", 30},
}
slices.SortStableFunc(people, func(a, b Person) int {
if a.Age < b.Age {
return -1
}
if a.Age > b.Age {
return 1
}
if a.Name < b.Name {
return -1
}
if a.Name > b.Name {
return 1
}
return 0
})
fmt.Println("Sorted people:")
for _, p := range people {
fmt.Printf("%s (%d)\n", p.Name, p.Age)
}
}
比较函数首先检查年龄,然后检查相同年龄下姓名。稳定排序会保留具有相同年龄和姓名的个人的原始顺序。
不区分大小写的字符串排序
此示例演示了不区分大小写的排序,同时保留了在不区分大小写的情况下相等字符串的原始顺序。
package main
import (
"fmt"
"slices"
"strings"
)
func main() {
words := []string{"Apple", "banana", "apple", "Banana", "cherry"}
slices.SortStableFunc(words, func(a, b string) int {
aLower := strings.ToLower(a)
bLower := strings.ToLower(b)
if aLower < bLower {
return -1
}
if aLower > bLower {
return 1
}
return 0
})
fmt.Println("Case-insensitive sorted:", words)
}
我们在比较前将字符串转换为小写。由于稳定排序,“Apple”和“apple”的原始顺序得到了保留。
降序排序
要按降序排序,我们只需反转比较逻辑。此示例将数字从最高到最低排序。
package main
import (
"fmt"
"slices"
)
func main() {
numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.SortStableFunc(numbers, func(a, b int) int {
if a > b {
return -1
}
if a < b {
return 1
}
return 0
})
fmt.Println("Descending sorted:", numbers)
}
比较函数在 a > b 时返回 -1 以实现降序。相等元素的原始相对位置将保持不变。
具有复杂逻辑的排序
slices.SortStableFunc 可以处理复杂的排序标准。此示例按长度对字符串进行排序,对于长度相等的字符串,则按字母顺序排序。
package main
import (
"fmt"
"slices"
)
func main() {
words := []string{"apple", "banana", "kiwi", "orange", "fig", "pear"}
slices.SortStableFunc(words, func(a, b string) int {
if len(a) < len(b) {
return -1
}
if len(a) > len(b) {
return 1
}
if a < b {
return -1
}
if a > b {
return 1
}
return 0
})
fmt.Println("Complex sorted:", words)
}
比较函数首先比较长度,然后对长度相等的字符串执行字典序比较。稳定排序会保留原始顺序。
实际示例:员工排序
这个实际示例按部门对员工进行排序,然后在部门内按薪资进行排序,在相等比较时保留原始顺序。
package main
import (
"fmt"
"slices"
)
type Employee struct {
Name string
Department string
Salary int
}
func main() {
employees := []Employee{
{"Alice", "HR", 50000},
{"Bob", "IT", 75000},
{"Charlie", "HR", 50000},
{"David", "IT", 80000},
{"Eve", "Finance", 60000},
}
slices.SortStableFunc(employees, func(a, b Employee) int {
if a.Department < b.Department {
return -1
}
if a.Department > b.Department {
return 1
}
if a.Salary < b.Salary {
return -1
}
if a.Salary > b.Salary {
return 1
}
return 0
})
fmt.Println("Sorted employees:")
for _, e := range employees {
fmt.Printf("%s: %s $%d\n", e.Name, e.Department, e.Salary)
}
}
员工首先按部门名称排序,然后在每个部门内按薪资排序。对于具有相同字段的员工,将保留原始顺序。
来源
本教程通过使用自定义比较函数的稳定排序的实际示例,介绍了 Go 中的 slices.SortStableFunc 函数。