代码之家  ›  专栏  ›  技术社区  ›  R2B2

在Go[closed]中对结构片进行排序的灵活而优雅的方法

go
  •  1
  • R2B2  · 技术社区  · 7 年前

    让我们说,我们有一个相当复杂的问题 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
    这将是一个完美的解决方案(参见 this answer ),但根据我的理解,排序函数必须内联指定(我得到一个错误) invalid receiver type []T ([]T is an unnamed type) 当我试图在别处定义它时,这意味着我需要为它定义一个别名 []T 我们回到解决方案1)。
    现在,定义内联函数的问题是(i)考虑到 MySuperType ,函数可以很长,(ii)函数将在多个地方重复(例如 f1 f3 在我上面的例子中)--比解决方案1更烦人,因为排序函数可能又长又复杂。

    问题:

    但是,有没有人知道一个不同的方法,优雅地解决这个问题或建议,以改善上述缺点?

    3 回复  |  直到 7 年前
        1
  •  2
  •   Jason Carlson    7 年前

    @ThunderCat的解决方案将起作用。另一种选择是编写返回 闭包 在一片与 less sort.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
        }
    }
    

    然后把它作为 arg到 sort.Slice :

    sort.Slice(mySuperSlice, ascX0DescX1(mySuperSlice))
    
        2
  •  3
  •   Cerise Limón    7 年前

    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
    }
    
        3
  •  0
  •   chriopp    7 年前

    您还可以省略额外的函数,并在需要时调用sort。

    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)
    }
    

    结果: