Go语言的sort函数
特点:
-
Go
语言的sort.Sort
函数不会对具体的序列和它的元素做任何假设用了一个接口类型sort.Interface
来指定通用的排序算法和可能被排序到的序列类型之间的约定。 -
接口的实现由序列的具体表示和它希望排序的元素决定,序列的表示经常是一个切片
sort.Interface定义的三个方法:
package sort
type Interface interface {
Len() int // 获取元素数量
Less(i, j int) bool // i,j是序列元素的指数。
Swap(i, j int) // 交换元素
}
使用要点:
需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用sort.Sort
函数
使用sort.Interface接口进行排序
定义一个类型,实现sort.Interface
接口当中的方法:
/*
将[]string定义为类型
Go的接口是隐式的,所以定义类型需要实现接口当中的方法
接口实现不受限于结构体,任何类型都可以实现接口。要排序的字符串切片 []string 是系统定制好的类型,无法让这个类型去实现 sort.Interface 排序接口。因此,需要将 []string 定义为自定义的类型
*/
type MyStringList []string
// 实现sort.Interface接口获取元素数量的方法
func (m MyStringList) Len() int {
return len(m)
}
// 实现sort.Interface比较元素的方法
func (m MyStringList) Less(i, j int) bool {
return m[i] < m[j]
}
// 实现sort.Interface交换元素的方法
func (m MyStringList) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
调用sort.Sort
方法进行排序:
func main() {
// 准备一个内容被打乱的字符串切片
/*
由于将 []string 定义成 MyStringList 类型,字符串切片初始化
*/
names := MyStringList{
"3, 这是三",
"4, 这是四",
"5, 这是五",
"1, 这是一",
"2, 这是二",
}
// 使用sort包进行排序
sort.Sort(names)
// 遍历打印结果
for _, v := range names {
fmt.Sprintf("%s\n", v)
}
}
names := MyStringList{}
写法等价于:
names := []string {
"3, 这是三",
"4, 这是四",
"5, 这是五",
"1, 这是一",
"2, 这是二",
}
sort.Sort包内常见的类型排序接口
类 型 | 实现 sort.lnterface 的类型 | 直接排序方法 | 说 明 |
---|---|---|---|
字符串(String) | StringSlice | sort.Strings(a [] string) | 字符 ASCII 值升序 |
整型(int) | IntSlice | sort.Ints(a []int) | 数值升序 |
双精度浮点(float64) | Float64Slice | sort.Float64s(a []float64) | 数值升序 |
经常用到的 int32、int64、float32、bool 类型并没有由 sort 包实现,使用时需要自己去实现sort.Interface
接口实现。
对结构体数据进行排序
注意:
结构体的不同属性有不同的排序规则
代码示例
定义一批英雄名单使用结构体,结构体中定义了英雄的名字和分类。排序时要求按照英雄的分类进行排序,相同分类的情况下按名字进行排序
package main
import (
"fmt"
"sort"
)
/*
声明分类
将 int 声明为 HeroKind 英雄类型,后面会将这个类型当做枚举来使用
*/
type HeroKind int
/*
定义类型
*/
type Hero struct {
Name string
Kind HeroKind
}
/*
定义指针切片类型
*/
type Heros []*Hero
/*
定义常量--->类似枚举类
*/
const (
None HeroKind = iota
Tank
Assassin
Mage
)
/*
实现sort.Interface的方法
*/
// 取接口元素数量
func (s Heros) Len() int {
return len(s)
}
// 比较接口元素
func (s Heros) Less(i, j int) bool {
// 先判断分类是否一致,分类不一致优先对分类进行排序
if s[i].Kind != s[j].Kind {
// 对分类进行排序
return s[i].Kind < s[j].Kind
}
// 默认按照名字升序排序
return s[i].Name < s[j].Name
}
// 交换元素位置
func (s Heros) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
/*
调用接口
*/
func main() {
// 准备数据
heros := Heros{
&Hero{"吕布", Tank},
&Hero{"李白", Assassin},
&Hero{"妲己", Mage},
&Hero{"貂蝉", Assassin},
&Hero{"关羽", Tank},
&Hero{"诸葛亮", Mage},
}
// 调用sort包排序
sort.Sort(heros)
// 遍历列表打印结果
for _, v := range