go 任意结构体多字段排序

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值