本文来自go语言圣经读书笔记
sort包内置的提供了根据一些排序函数来对任何序列排序的功能。它的设计非常独到。
在很多语言中,排序算法都是和序列数据类型关联,同时排序函数和具体类型元素关联。
而Go语言的sort.Sort函数不会对具体的序列和它的元素做任何假设。
它使用了一个接口类型sort.Interface来指定通用的排序算法和可能被排序到的序列类型之间的约定。这个接口的实现由序列的具体表示和它希望排序的元素决定,序列的表示经常是一个切片。
package sort
type Interface interface {
Len() int
Less(i, j int) bool // i, j are indices of sequence elements
Swap(i, j int)
}
我们需要定义一个排序类型的切片,这个实现了这三个方法,然后再对这个类型的一个实例调用sort.Sort函数。
以下为对一个字符串切片进行排序
//切片
type StringSlice []string
//
func (p StringSlice) Len() int{
return len(p)
}
//
func (p StringSlice) Less(i, j int) bool {
return p[i] < p[j]
}
//
func (p StringSlice) Swap(i, j int){
p[i], p[j] = p[j], p[i]
}
对字符串切片是很常用的需要,所以sort包提供了StringSlic类型,也提供了sort.Strings(name)
反向排序,奇妙的实现方法 不需要重新定义一个Less方法,只需要使用
sort.Sort(sort.Reverse(StringSlice(name)))
Reverse的底层实现是定义了一个不公开的类,成员是第六章里讲的那个匿名成员
reverse的Less方法调用了内嵌的sort.Interface值的Less方法,但是通过交换索引的方式使排序结果变成逆序。
reverse的另外两个方法Len和Swap隐式地由原有内嵌的sort.Interface提供。
type reverse struct{ Interface } // sort.Interface
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }
func Reverse(data Interface) Interface { return reverse{data} }
难道按每个字段排序,只能对比一个字段吗?而且每次都要实现实现3个方法吗?下面的例子利用结构体来做到了只需要重写Less方法即可,本质上用的是go中的函数为一等公民(函数值)的特点。
type customSort struct {
t []*Track
//只需要传入不同的less函数就可以做到不同的排序
less func(x, y *Track) bool
}
func (x customSort) Len() int {
return len(x.t)
}
func (x customSort) Less(i, j int) bool {
return x.less(x.t[i], x.t[j])
}
func (x customSort) Swap(i, j int) {
x.t[i], x.t[j] = x.t[j], x.t[i]
}
//调用方法,传入了一个匿名函数
sort.Sort(customSort{tracks, func(x, y *Track) bool {
if x.Title != y.Title {//先比较Title
return x.Title < y.Title
}
if x.Year != y.Year {//再比较Year
return x.Year < y.Year
}
if x.Length != y.Length {//再比较Length
return x.Length < y.Length
}
//如果上面三个都相等
return false
}})
sort包为[]int、[]string和[]float64的正常排序提供了特定版本的函数和类型。对于其他类型,例如[]int64或者[]uint,尽管路径也很简单,还是依赖我们自己实现。
原文:https://www.cnblogs.com/Jun10ng/p/12860555.html