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

假设我们有一个相当复杂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 applyCriteria2b


func 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。

但是有没有人知道可以优雅地解决这个问题的不同方法或改进上面列出的缺点的建议?


一只斗牛犬
浏览 117回答 3
3回答

慕村9548890

另一种选择是编写函数,返回与参数签名匹配的切片上的闭包:lesssort.Slicefunc ascX0DescX1(s []MySuperType) (func(int, int) bool) {&nbsp; &nbsp; return func(i, j int) bool {&nbsp; &nbsp; &nbsp; &nbsp; if s[i].x0 == s[j].x0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return s[i].x1 > s[j].x1&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return s[i].x0 < s[j].x0&nbsp; &nbsp; }}然后将其作为lessarg传递给sort.Slice:sort.Slice(mySuperSlice, ascX0DescX1(mySuperSlice))

慕斯709654

为每个排序编写一个排序函数,并根据需要从 f1、f2 和 f3 调用:func sortByX0AscX1Desc(s []MySuperType) {&nbsp; &nbsp; sort.Slice(s, func(i, j int) bool {&nbsp; &nbsp; &nbsp; &nbsp; switch {&nbsp; &nbsp; &nbsp; &nbsp; case s[i].x0 < s[j].x0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true&nbsp; &nbsp; &nbsp; &nbsp; case s[i].x0 > s[j].x0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; &nbsp; &nbsp; case s[i].x1 > s[j].x1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })}func f1(mySuperSlice []MySuperType) {&nbsp; &nbsp; sortByX0AscX1Desc(mySuperSlice)&nbsp; &nbsp; // do something with the sorted list}func f2(mySuperSlice []MySuperType) {&nbsp; &nbsp; sortBySomethingElse(mySuperSlice)&nbsp; &nbsp; // do something with the sorted list}func f3(mySuperSlice []MySuperType) {&nbsp; &nbsp; sortByX0AscX1Desc(mySuperSlice)&nbsp; &nbsp; // do something with the sorted list}

慕运维8079593

您也可以省略额外的功能并在需要的地方调用排序。type MySuperType struct {&nbsp; &nbsp; x0, x1, x2, x3 string}func f1() {&nbsp; &nbsp; fields := []MySuperType {&nbsp; &nbsp; &nbsp; &nbsp; { "a1", "b4", "c3", "d2" },&nbsp; &nbsp; &nbsp; &nbsp; { "a2", "b1", "c2", "d3" },&nbsp; &nbsp; &nbsp; &nbsp; { "a3", "b1", "c4", "d1" },&nbsp; &nbsp; &nbsp; &nbsp; { "a4", "b3", "c1", "d4" },&nbsp; &nbsp; }&nbsp; &nbsp; sort.SliceStable(fields, func(i, j int) bool {&nbsp; &nbsp; &nbsp; &nbsp; return fields[i].x1 < fields[j].x1 || fields[i].x2 > fields[j].x2&nbsp; &nbsp; })&nbsp; &nbsp; 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}]
打开App,查看更多内容
随时随地看视频慕课网APP