今天写代码,牵扯到给一个slice排序的问题,发现go的sort包里支持自定义排序,果断拿来用了。
sort.Slice(priceList, func(i, j int) bool {
return priceList[i].RenewDate > priceList[j].RenewDate
})
上面这个是使用sort.Slice()
的例子。
在此之前,先讲讲基础的Sort方法,
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}
func quickSort(data Interface, a, b, maxDepth int) {
.
.
.
}
我们发现,要实现sort排序,我们需要实现sort接口的三个方法,分别是Len()
,Less(i, j int) bool
,和Swap(i, j int)
。这三个方法的注释上面都有,我就不解释了。它接收Interface接口,拿到了Interface接口,就可以去调用实现了这个接口的类型所对应的三个方法。Sort方法内部会去调一个快排算法,既然是快排算法,里面肯定用到了less和swap,所以内部实现就不贴出来了。所以针对一般的sort.Sort(某个切片)
,使用例子如下:
type Person struct {
Name string
Age int
}
type PersonSlice [] Person
func (a PersonSlice) Len() int { // 重写 Len() 方法
return len(a)
}
func (a PersonSlice) Swap(i, j int){ // 重写 Swap() 方法
a[i], a[j] = a[j], a[i]
}
func (a PersonSlice) Less(i, j int) bool { // 重写 Less() 方法, 从大到小排序
return a[j].Age < a[i].Age
}
func main() {
people := [] Person{
{"zhang wan", 15},
{"li zi", 31},
{"wang su", 32},
{"zhao miu", 28},
}
sort.Sort(PersonSlice(people)) // 按照 Age 的逆序排序,参数传递给接口
fmt.Println(people)
接下来讲一个更高效的,那就是sort.Slice()
方法了,
sort.Slice(priceList, func(i, j int) bool {
return priceList[i].RenewDate > priceList[j].RenewDate
})//使用
func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}//源码
如上所述,我直接写一个less函数作为函数对象传给Slice方法,这里其实相当于callback的思想了,然后swap和len方法系统帮我自动实现,len就是我的第一个参数的长度,swap用系统默认的交换算法,这样我就高效的编写了一个可以由我自己来定义排序顺序的struct切片排序,不仅简洁优雅,代码量小,而且容易被人理解,真是又一次体会到了go的魅力。