引入
Go time 包 能计算时间差,但如果有多个事件要按时间排列呢?Go 的 sort 包提供通用的排序功能,能对切片和自定义类型进行排序,是数据处理中的基本工具。
正文
定义
定义
sort包提供排序和搜索功能。内置函数直接排序int、float64、string切片,sort.Slice能对任意切片按自定义规则排序,sort.Search实现二分搜索。
语法
import "sort"
// 内置排序
sort.Ints(a) // 排序 int 切片
sort.Float64s(f) // 排序 float64 切片
sort.Strings(s) // 排序 string 切片
// 自定义排序
sort.Slice(slice, func(i, j int) bool {
return slice[i] < slice[j]
})例子
排序 int 切片
nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
sort.Ints(nums)
fmt.Println(nums) // [1 1 2 3 4 5 6 9]
// 是否已排序
fmt.Println(sort.IntsAreSorted(nums)) // truesort.Ints 原地排序,直接修改原切片。sort.IntsAreSorted 检查是否已排序。
排序 string 切片
words := []string{"banana", "apple", "cherry"}
sort.Strings(words)
fmt.Println(words) // [apple banana cherry]sort.Strings 按字典序排序。
排序 float64 切片
scores := []float64{3.14, 2.71, 1.41, 1.73}
sort.Float64s(scores)
fmt.Println(scores) // [1.41 1.73 2.71 3.14]sort.Slice:自定义排序
nums := []int{3, 1, 4, 1, 5, 9}
// 降序排列
sort.Slice(nums, func(i, j int) bool {
return nums[i] > nums[j]
})
fmt.Println(nums) // [9 5 4 3 1 1]sort.Slice 第二个参数是比较函数,返回 true 表示 i 排在 j 前面。想要降序就把 > 换成 <。
排序结构体切片
type User struct {
Name string
Age int
}
users := []User{
{"Tom", 20},
{"Alice", 25},
{"Bob", 18},
}
// 按年龄升序
sort.Slice(users, func(i, j int) bool {
return users[i].Age < users[j].Age
})
// [Bob 18, Tom 20, Alice 25]
// 按名字字典序
sort.Slice(users, func(i, j int) bool {
return users[i].Name < users[j].Name
})
// [Alice 25, Bob 18, Tom 20]sort.Slice 最强大的地方就是能对任意切片按任意字段排序。比较函数里写排序逻辑就行。
稳定排序
type Event struct {
Name string
Day int
}
events := []Event{
{"A", 1}, {"B", 2}, {"C", 1}, {"D", 2},
}
sort.SliceStable(events, func(i, j int) bool {
return events[i].Day < events[j].Day
})
// [A 1, C 1, B 2, D 2] — 同 Day 保持原顺序sort.Slice 不保证相等元素的顺序,sort.SliceStable 保证相等元素维持原始顺序。
二分搜索
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
i := sort.SearchInts(nums, 5)
fmt.Println(i) // 4(索引)
// 通用二分搜索
i = sort.Search(len(nums), func(k int) bool {
return nums[k] >= 5
})
fmt.Println(i) // 4二分搜索要求切片已排序。sort.Search 返回第一个使条件为 true 的索引。
sort.Reverse
nums := []int{3, 1, 4, 1, 5}
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
fmt.Println(nums) // [5 4 3 1 1]sort.Reverse 反转排序顺序。配合 sort.IntSlice、sort.StringSlice 等类型转换使用。
常见写法
| 写法 | 说明 |
|---|---|
sort.Ints(a) | 排序 int 切片(升序) |
sort.Strings(s) | 排序 string 切片 |
sort.Float64s(f) | 排序 float64 切片 |
sort.Slice(s, less) | 自定义排序任意切片 |
sort.SliceStable(s, less) | 稳定排序 |
sort.IntsAreSorted(a) | 检查是否已排序 |
sort.SearchInts(a, v) | 在 int 切片中二分搜索 |
sort.SearchStrings(s, v) | 在 string 切片中二分搜索 |
sort.Search(n, f) | 通用二分搜索 |
sort.Reverse(data) | 反转排序顺序 |
特点
sort.Ints/sort.Strings/sort.Float64s是原地排序,直接修改原切片sort.Slice能对任意类型切片排序,比较函数决定排序规则sort.SliceStable保持相等元素的原始顺序,多级排序时需要- 二分搜索要求切片已排序,否则会返回错误结果
- 排序是 O(n log n) 复杂度,大数据量也能接受
- Go 1.21+ 引入了泛型版本
slices.Sort,写法更简洁
理解
sort 包的核心思路很简单:内置函数处理常见类型(int、string、float64),sort.Slice 一个函数搞定所有自定义排序。写比较函数就记住一点——返回 true 表示 i 应该排在 j 前面。升序用 <,降序用 >。SliceStable 在需要保持相对顺序时别用错了。
引出
排序经常配合文件数据使用——从文件读取数据、排序后写回去。接下来看 Go 文件操作,学习 Go 中读写文件的各种方式。