go 任意结构体多字段排序
- 背景:有时候需要对一个结构体的多个字段进行排序,排序维度是可以定制的。但是更需要对任意结构体都可以使用自定义字段进行排序。
- 实现:参考博客
- 改进:实现了任意结构体。对,很简单就是使用了interface。
package main
import (
"fmt"
"sort"
)
// sort接口方法之一(Less)
type alessFunc func(p1, p2 interface{}) bool
// 数据集类型, 与排序(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *interface{}) bool
// 而是 []func(p1, p2 *interface{}) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type amultiSorter struct {
RealOrderCntDbs []interface{}
less []alessFunc
}
type OrderedBya []alessFunc
func (ob OrderedBya) Sorta(RealOrderCntDbs []interface{}) {
ms := &amultiSorter{
RealOrderCntDbs: RealOrderCntDbs,
less: ob,
}
sort.Sort(ms)
}
// Len 为sort接口方法之一
func (ms *amultiSorter) Len() int {
return len(ms.RealOrderCntDbs)
}
// Swap 为sort接口方法之一
func (ms *amultiSorter) Swap(i, j int) {
ms.RealOrderCntDbs[i], ms.RealOrderCntDbs[j] = ms.RealOrderCntDbs[j], ms.RealOrderCntDbs[i]
}
// Less 为sort接口方法之一 默认是降序
func (ms *amultiSorter) Less(i, j int) bool {
// 为了后面编写简便, 这里将需要比较的两个元素赋值给两个单独的变量
p, q := ms.RealOrderCntDbs[i], ms.RealOrderCntDbs[j]
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q): // less是字段降序的话,p>q 则直接返回true
fmt.Println("less p,q", p, q)
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p): // less是字段降序的话,p>q 则直接返回true
fmt.Println("less q,p", p, q)
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
fmt.Println(p, q)
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}
func main() {
buyGroup := make([]interface{}, 0) // 切片
buyGroup = append(buyGroup,
&testData{
BuyCount: 1,
Sales: 5,
SalesPage: 8,
},
&testData{
BuyCount: 3,
Sales: 4,
SalesPage: 10,
},
&testData{
BuyCount: 9,
Sales: 4,
SalesPage: 10,
},
)
// 预定义排序函数: 按照 Sales 降序
var ma = func(c1, c2 interface{}) bool {
return c1.(*testData).Sales > c2.(*testData).Sales
}
// 预定义排序函数: 按照订购编码+pageid降序
var mb = func(c1, c2 interface{}) bool {
return c1.(*testData).BuyCount > c2.(*testData).BuyCount
}
// 排序
lessFuncs := []alessFunc{} // 排序方法
fmt.Println(ma, mb)
lessFuncs = append(lessFuncs, ma)
lessFuncs = append(lessFuncs, mb)
OrderedBya(lessFuncs).Sorta(buyGroup)
for _, item := range buyGroup {
fmt.Println(item.(*testData).Sales, item.(*testData).BuyCount, item.(*testData).SalesPage)
}
}
type testData struct {
BuyCount int32
Sales int32
SalesPage int32
}
结果
5 1 8
4 9 10
4 3 10