• 1.26 Go语言之排序(sort.Interface接口)


    1.26 Go语言之排序(sort.Interface接口)

    Go语言的sort函数

    特点:

    • Go语言的sort.Sort函数不会对具体的序列和它的元素做任何假设用了一个接口类型sort.Interface来指定通用的排序算法和可能被排序到的序列类型之间的约定。

    • 接口的实现由序列的具体表示和它希望排序的元素决定,序列的表示经常是一个切片

    sort.Interface定义的三个方法:

    package sort
    type Interface interface {
       Len() int            // 获取元素数量
       Less(i, j int) bool // i,j是序列元素的指数。
       Swap(i, j int)        // 交换元素
    }

    使用要点:

    需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用sort.Sort函数

    使用sort.Interface接口进行排序

    定义一个类型,实现sort.Interface接口当中的方法:

    /*
    将[]string定义为类型
    Go的接口是隐式的,所以定义类型需要实现接口当中的方法
    接口实现不受限于结构体,任何类型都可以实现接口。要排序的字符串切片 []string 是系统定制好的类型,无法让这个类型去实现 sort.Interface 排序接口。因此,需要将 []string 定义为自定义的类型
    */
    type MyStringList []string

    // 实现sort.Interface接口获取元素数量的方法
    func (m MyStringList) Len() int {
       return len(m)
    }

    // 实现sort.Interface比较元素的方法
    func (m MyStringList) Less(i, j int) bool {
       return m[i] < m[j]
    }

    // 实现sort.Interface交换元素的方法
    func (m MyStringList) Swap(i, j int) {
       m[i], m[j] = m[j], m[i]
    }

    调用sort.Sort方法进行排序:

    func main() {
       // 准备一个内容被打乱的字符串切片
       /*
       由于将 []string 定义成 MyStringList 类型,字符串切片初始化
        */
       names := MyStringList{
           "3, 这是三",
           "4, 这是四",
           "5, 这是五",
           "1, 这是一",
           "2, 这是二",
      }

       // 使用sort包进行排序
       sort.Sort(names)

       // 遍历打印结果
       for _, v := range names {
           fmt.Sprintf("%s\n", v)
      }
    }

    names := MyStringList{}写法等价于:

    names := []string {
       "3, 这是三",
       "4, 这是四",
       "5, 这是五",
       "1, 这是一",
       "2, 这是二",
    }

    sort.Sort包内常见的类型排序接口

    类 型实现 sort.lnterface 的类型直接排序方法说 明
    字符串(String) StringSlice sort.Strings(a [] string) 字符 ASCII 值升序
    整型(int) IntSlice sort.Ints(a []int) 数值升序
    双精度浮点(float64) Float64Slice sort.Float64s(a []float64) 数值升序

    经常用到的 int32、int64、float32、bool 类型并没有由 sort 包实现,使用时需要自己去实现sort.Interface接口实现。

    对结构体数据进行排序

    注意:

    结构体的不同属性有不同的排序规则

    代码示例

    定义一批英雄名单使用结构体,结构体中定义了英雄的名字和分类。排序时要求按照英雄的分类进行排序,相同分类的情况下按名字进行排序

    package main

    import (
       "fmt"
       "sort"
    )

    /*
    声明分类
    将 int 声明为 HeroKind 英雄类型,后面会将这个类型当做枚举来使用
    */
    type HeroKind int

    /*
    定义类型
    */
    type Hero struct {
       Name string
       Kind HeroKind
    }

    /*
    定义指针切片类型
    */
    type Heros []*Hero

    /*
    定义常量--->类似枚举类
    */
    const (
       None HeroKind = iota
       Tank
       Assassin
       Mage
    )

    /*
    实现sort.Interface的方法
    */
    // 取接口元素数量
    func (s Heros) Len() int {
       return len(s)
    }

    // 比较接口元素
    func (s Heros) Less(i, j int) bool {
       // 先判断分类是否一致,分类不一致优先对分类进行排序
       if s[i].Kind != s[j].Kind {
           // 对分类进行排序
           return s[i].Kind < s[j].Kind
      }

       // 默认按照名字升序排序
       return s[i].Name < s[j].Name
    }

    // 交换元素位置
    func (s Heros) Swap(i, j int) {
       s[i], s[j] = s[j], s[i]
    }

    /*
    调用接口
    */
    func main() {
       // 准备数据
       heros := Heros{
           &Hero{"吕布", Tank},
           &Hero{"李白", Assassin},
           &Hero{"妲己", Mage},
           &Hero{"貂蝉", Assassin},
           &Hero{"关羽", Tank},
           &Hero{"诸葛亮", Mage},
      }

       // 调用sort包排序
       sort.Sort(heros)

       // 遍历列表打印结果
       for _, v := range heros {
           fmt.Printf("%v\n", v)
      }
    }

    使用sort.Slice进行切片排序

    特点:

    我们知道Go当中是隐式的实现接口。但是依然需要实现接口当中的全部的方法。否则就会报错。

    sort.Slice提供了更为简便的排序方法。入参只有:数据+排序时对元素的回调函数即可:

    func Slice(slice interface{}, less func(i, j int) bool)

    代码示例

    package main

    import (
       "fmt"
       "sort"
    )

    /*
    定义分类
    */
    type herokind int

    /*
    定义枚举常数
    */
    const (
       none herokind = iota
       tank
       assassin
       mage
    )

    /*
    定义类型
    */
    type hero struct {
       name string
       kind herokind
    }

    /*
    调用
    */
    func main() {
       heros := []*hero{
          {"吕布", tank},
          {"李白", assassin},
          {"妲己", mage},
          {"貂蝉", assassin},
          {"关羽", tank},
          {"诸葛亮", mage},
      }

       // 调用sort.Slice函数
       sort.Slice(heros, func(i, j int) bool {
           if heros[i].kind != heros[j].kind {
               return heros[i].kind < heros[j].kind
          }
           return heros[i].name < heros[j].name
      })

       // 循环输出切片中的值
       for _, v := range heros {
           fmt.Printf("%v\n", v)
      }
    }

    特点:

    传入回调函数就可以直观的看出本次操作执行了的函数是什么。而不是使用类型实现sort.Interface接口下全部的方法

    使用sort.Slice()不仅可以完成结构体切片排序,还可以对各种切片类型进行自定义排序。

  • 相关阅读:
    SQL Server 2005 全文搜索包括改进和更新的干扰词文件FROM MS KB
    服务器内存选项From MS
    跳过事务复制中的错误
    WP7基础补充
    TaoBaoAPI简介3
    登录功能代码
    TaoBaoApI简介1
    TaoBaoAPI简介2
    WP7基础学习第十三讲
    WP7基础学习第十四讲
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/15944264.html
Copyright © 2020-2023  润新知