为了账号安全,请及时绑定邮箱和手机立即绑定

一种在 Go 中对结构切片进行排序的灵活而优雅的方法

一种在 Go 中对结构切片进行排序的灵活而优雅的方法

Go
一只斗牛犬 2023-04-04 17:23:07
假设我们有一个相当复杂struct的领域,我需要根据不同的标准在几个地方进行排序,例如type MySuperType struct {    x0, x1, x2, x3 xType    // possibly even more fields}// sort 1: ascending x0, then descending x1, then more stuff// sort 2: if x4==0 then applyCriteria2a else applyCriteria2bfunc f1(mySuperSlice []MySuperType) {    // sort 'myList' according sort #1    // do something with the sorted list}func f2(mySuperSlice []MySuperType) {    // sort 'myList' according sort #2    // do something with the sorted list}func f3(mySuperSlice []MySuperType) {    // sort 'myList' according sort #1, note: we use sort #1 again!    // do something with the sorted list}建议的解决方案 1:创建一个新类型(别名[]MySuperType)来实现sort.Interface所需的每个排序标准。问题:(i)有一些重复的代码,因为函数Len和Swap将是相同的(ii)将会有一堆新的类型,它们对程序的整体可读性没有帮助——这些新类型并不真正代表任何东西,而且唯一真正重要的是函数Less。建议的解决方案 2:使用sort.Slice这将是完美的解决方案(请参阅此答案),但据我了解,必须内联指定排序功能(invalid receiver type []T ([]T is an unnamed type)当我尝试在其他地方定义它时出现错误,这意味着我需要定义的别名[]T,我们回到解决方案 1)。现在,定义内联函数的问题是(i)考虑到 的复杂性MySuperType,函数可能会很长,并且(ii)函数将在几个地方重复(例如f1在f3我上面的例子中)——比解决方案 1 更烦人的是排序函数可能又长又复杂。注意:(i) 如果我们实际上没有 (ii) 就不会是那么大的问题问题:鉴于我目前对 Go 的理解和知识,我会使用解决方案 1。但是有没有人知道可以优雅地解决这个问题的不同方法或改进上面列出的缺点的建议?
查看完整描述

3 回答

?
慕村9548890

TA贡献1884条经验 获得超4个赞

另一种选择是编写函数,返回与参数签名匹配的切片上的闭包:lesssort.Slice


func ascX0DescX1(s []MySuperType) (func(int, int) bool) {

    return func(i, j int) bool {

        if s[i].x0 == s[j].x0 {

            return s[i].x1 > s[j].x1

        }

        return s[i].x0 < s[j].x0

    }

}

然后将其作为lessarg传递给sort.Slice:


sort.Slice(mySuperSlice, ascX0DescX1(mySuperSlice))


查看完整回答
反对 回复 2023-04-04
?
慕斯709654

TA贡献1840条经验 获得超5个赞

为每个排序编写一个排序函数,并根据需要从 f1、f2 和 f3 调用:


func sortByX0AscX1Desc(s []MySuperType) {

    sort.Slice(s, func(i, j int) bool {

        switch {

        case s[i].x0 < s[j].x0:

            return true

        case s[i].x0 > s[j].x0:

            return false

        case s[i].x1 > s[j].x1:

            return true

        default:

            return false

        }

    })

}


func f1(mySuperSlice []MySuperType) {

    sortByX0AscX1Desc(mySuperSlice)

    // do something with the sorted list

}

func f2(mySuperSlice []MySuperType) {

    sortBySomethingElse(mySuperSlice)

    // do something with the sorted list

}

func f3(mySuperSlice []MySuperType) {

    sortByX0AscX1Desc(mySuperSlice)

    // do something with the sorted list

}


查看完整回答
反对 回复 2023-04-04
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

您也可以省略额外的功能并在需要的地方调用排序。


type MySuperType struct {

    x0, x1, x2, x3 string

}


func f1() {

    fields := []MySuperType {

        { "a1", "b4", "c3", "d2" },

        { "a2", "b1", "c2", "d3" },

        { "a3", "b1", "c4", "d1" },

        { "a4", "b3", "c1", "d4" },

    }

    sort.SliceStable(fields, func(i, j int) bool {

        return fields[i].x1 < fields[j].x1 || fields[i].x2 > fields[j].x2

    })

    fmt.Println("by x1, then x2: ", fields)

}

结果:通过 x1,然后 x2:[{a3 b1 c4 d1} {a2 b1 c2 d3} {a4 b3 c1 d4} {a1 b4 c3 d2}]


查看完整回答
反对 回复 2023-04-04
  • 3 回答
  • 0 关注
  • 112 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信