美文网首页
golang sort.Slice踩坑记录

golang sort.Slice踩坑记录

作者: 夕午wuw | 来源:发表于2022-09-14 17:38 被阅读0次

    sort.Slice

    sort.Slice是go 1.8版本引入的一个强大排序函数。第一个参数是待排序的任意类型slice;第二个参数是less function,用于比较 i 和 j 对应的元素大小,"较小"的排在前面。注意这里并不真的按照"大小"排序,而是根据less func的定义来决定排序。
    func Slice(x any, less func(i, j int) bool)

    import (
        "fmt"
        "sort"
    )
    
    func main() {
        people := []struct {
            Name string
            Age  int
        }{
            {"Gopher", 7},
            {"Alice", 55},
            {"Vera", 24},
            {"Bob", 75},
        }
        sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
        fmt.Println("By name:", people)
    
        sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
        fmt.Println("By age:", people)
    }
    

    上面这段代码就很好的展示了less function的强大。但同时也需要注意,这里的less function是一个匿名函数,存在的坑接下来我会细说。

    匿名函数小坑

    假设我们现在要对一个int slice进行排序,小的在前面。很容易写出以下代码:

    func sortAll(nums []int) {
        sort.Slice(nums, func(i, j int) bool {
            return nums[i] < nums[j]
        })
    }
    

    接下来,坑来了。如果我只想对int slice的后半部分进行排序,怎么办?以下代码可行吗:

    func sortPartly(nums []int, p int) { // 从p开始排序
         sort.Slice(nums[p:], func(i, j int) bool { // 这里传入的slice不再是完整的nums,而是nums[p:]
             return nums[i] < nums[j]
        })
    } // 错误写法
    

    乍一看是可以的,但由于匿名函数的原因,这个写法不可行。在上面那段代码中,需要排序的slice是nums,对于slice中的第i或者第j个元素,less function直接对nums[i]和nums[j]进行比较操作;而在下面那段代码中,需要排序的slice是 nums[:p] ,对于slice中的第i或者第j个元素,less function 仍然是对nums[i]和nums[j] 进行比较操作。实际上,less function应该比较的对象是 nums[i+p]和nums[j+p]
    因此,一个正确的部分排序函数应该这样写,对less function的index进行调整:

    func sortPartly(nums []int, p int) {
        sort.Slice(nums[p:], func(i, j int) bool {
           return nums[i+p] < nums[j+p]
        })
    }
    

    那么,还有另一种优雅一些的写法: 对需要排序的部分新建立一个slice (go语言中的slice都是对一个底层数组的引用),再进行排序。这样就无需调整less function的index。

    func sortPartly(nums []int, p int) {
        t := nums[p:]
        sort.Slice(t, func(i, j int) bool {
            return t[i] < t[j]
        })
    }
    

    相关文章

      网友评论

          本文标题:golang sort.Slice踩坑记录

          本文链接:https://www.haomeiwen.com/subject/woxdortx.html