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
函数。