sort接口

一个很好的例子是来自标准库的 sort 包,要对一组数字或字符串排序,只需要实现三个方法:反映元素个数的 Len() 方法、比较第 i 和 j 个元素的 Less(i, j) 方法以及交换第 i 和 j 个元素的 Swap(i, j) 方法。

排序函数的算法只会使用到这三个方法(可以使用任何排序算法来实现,此处我们使用冒泡排序):

func Sort(data Sorter) {for pass := 1; pass < data.Len(); pass++ {for i := 0;i < data.Len() - pass; i++ {if data.Less(i+1, i) {data.Swap(i, i + 1)}}}
}

Sort 函数接收一个接口类型参数:Sorter ,它声明了这些方法:

type Sorter interface {Len() intLess(i, j int) boolSwap(i, j int)
}

参数中的 int 是待排序序列长度的类型,而不是说要排序的对象一定要是一组 int。i 和 j 表示元素的整型索引,长度也是整型的。

现在如果我们想对一个 int 数组进行排序,所有必须做的事情就是:为数组定一个类型并在它上面实现 Sorter 接口的方法:

type IntArray []int
func (p IntArray) Len() int           { return len(p) }
func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
func (p IntArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

下面是调用排序函数的一个具体例子:

data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
a := sort.IntArray(data) //conversion to type IntArray from package sort
sort.Sort(a)

同样的原理,排序函数可以用于一个浮点型数组,一个字符串数组,或者一个表示每周各天的结构体 dayArray.

示例 11.6 sort.go:

package sorttype Sorter interface {Len() intLess(i, j int) boolSwap(i, j int)
}func Sort(data Sorter) {for pass := 1; pass < data.Len(); pass++ {for i := 0; i < data.Len()-pass; i++ {if data.Less(i+1, i) {data.Swap(i, i+1)}}}
}func IsSorted(data Sorter) bool {n := data.Len()for i := n - 1; i > 0; i-- {if data.Less(i, i-1) {return false}}return true
}// Convenience types for common cases
type IntArray []intfunc (p IntArray) Len() int           { return len(p) }
func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
func (p IntArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }type StringArray []stringfunc (p StringArray) Len() int           { return len(p) }
func (p StringArray) Less(i, j int) bool { return p[i] < p[j] }
func (p StringArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }// Convenience wrappers for common cases
func SortInts(a []int)       { Sort(IntArray(a)) }
func SortStrings(a []string) { Sort(StringArray(a)) }func IntsAreSorted(a []int) bool       { return IsSorted(IntArray(a)) }
func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) }

示例 11.7 sortmain.go:

package mainimport ("./sort""fmt"
)func ints() {data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}a := sort.IntArray(data) //conversion to type IntArraysort.Sort(a)if !sort.IsSorted(a) {panic("fails")}fmt.Printf("The sorted array is: %v\n", a)
}func strings() {data := []string{"monday", "friday", "tuesday", "wednesday", "sunday", "thursday", "", "saturday"}a := sort.StringArray(data)sort.Sort(a)if !sort.IsSorted(a) {panic("fail")}fmt.Printf("The sorted array is: %v\n", a)
}type day struct {num       intshortName stringlongName  string
}type dayArray struct {data []*day
}func (p *dayArray) Len() int           { return len(p.data) }
func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
func (p *dayArray) Swap(i, j int)      { p.data[i], p.data[j] = p.data[j], p.data[i] }func days() {Sunday    := day{0, "SUN", "Sunday"}Monday    := day{1, "MON", "Monday"}Tuesday   := day{2, "TUE", "Tuesday"}Wednesday := day{3, "WED", "Wednesday"}Thursday  := day{4, "THU", "Thursday"}Friday    := day{5, "FRI", "Friday"}Saturday  := day{6, "SAT", "Saturday"}data := []*day{&Tuesday, &Thursday, &Wednesday, &Sunday, &Monday, &Friday, &Saturday}a := dayArray{data}sort.Sort(&a)if !sort.IsSorted(&a) {panic("fail")}for _, d := range data {fmt.Printf("%s ", d.longName)}fmt.Printf("\n")
}func main() {ints()strings()days()
}

输出:

The sorted array is: [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]
The sorted array is: [ friday monday saturday sunday thursday tuesday wednesday]
Sunday Monday Tuesday Wednesday Thursday Friday Saturday

备注:

上面的例子帮助我们进一步了解了接口的意义和使用方式。对于基本类型的排序,标准库已经提供了相关的排序函数,所以不需要我们再重复造轮子了。对于一般性的排序,sort 包定义了一个接口:

type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
这个接口总结了需要用于排序的抽象方法,函数 Sort(data Interface) 用来对此类对象进行排序,可以用它们来实现对其他数据(非基本类型)进行排序。在上面的例子中,我们也是这么做的,不仅可以对 int 和 string 序列进行排序,也可以对用户自定义类型 dayArray 进行排序。

golang 中的sort 包相关推荐

  1. golang中container/list包中的坑

    转载地址:golang中container/list包中的坑 - Go语言中文网 - Golang中文社区 golang中list包用法可以参看golang中container/list包用法_che ...

  2. golang中os/signal包的使用

    golang中os/signal包的使用 os/signal包实现对信号的处理 golang中对信号的处理主要使用os/signal包中的两个方法:一个是notify方法用来监听收到的信号:一个是 s ...

  3. Golang中log日志包的使用

    文章目录 1.前言 2.log包介绍 3.log包的使用 3.1 日志输出方法 3.2 自定义创建日志对象 3.3 封装自定义日志包 3.4 log包进一步解析 1.前言 作为后端开发人员,日志文件记 ...

  4. 深入理解Golang中的Context包

    context.Context是Go语言中独特的设计,在其他编程语言中我们很少见到类似的概念.context.Context深度支持Golang的高并发. 1. Goroutine和Channel 在 ...

  5. Golang中import 导入包的几种方式:点,别名与下划线

    在写Go代码的时候经常用到import这个命令用来导入包文件,看到的方式参考如下: import (// 多个"google.golang.org/grpc""imcs/ ...

  6. golang中的os包

    简介 介绍Go 标准库 os 常用导出函数,结构体及其方法. import os os 包提供了不依赖平台的操作系统函数接口.错误处理设计为go 风格,失败的调用会返回错误值而非错误码.通常错误值里包 ...

  7. Golang中path/filepath包

    path/filepath包下的相关函数 1. ToSlash函数 func ToSlash(path string) string 功能:将path中平台相关的路径分隔符转换成'/' 例如:wind ...

  8. Golang 中 sync/atomic 包的原子操作

    背景 Go中多协程的情况下, 要保证操作的原子性,一般要使用RWMutex或者Mutex, 但是锁使用起来比较复杂,还要考虑lock 和unlock 顺序和成对出现,不注意就容易出错. 于是在sync ...

  9. golang中json解析包

    package main import "github.com/tidwall/gjson" func main() { jsonstr1 := `{"richtext& ...

最新文章

  1. 使用CleanIISLog清除IIS记录
  2. 数据库集群技术 -摘自网络
  3. MyEclipse和tomcat结合编写jsp对于中文乱码的解决方法
  4. 在线应用的 Serverless 实践
  5. cx是什么简称_80年的5角,在纸币收藏界简称为8005
  6. php 动态修改函数,php – 动态调用函数
  7. 第9章 SportsStorePeta 完成购物车
  8. git学习笔记-(3-linux基本命令)
  9. 解决在RHEL/CentOS7.4以上版本无法使用AFD(Oracle ASMFD)特性
  10. Oracle练习题(三)
  11. 【微信小程序】--注册小程序账号安装开发者工具(一)
  12. 面向对象的特征之一:抽象
  13. 如何调整PDF的页面布局
  14. java窗体背景图片_java 窗体设置背景图片问题 (附上登陆界面代码,我想加个背景图...
  15. IT行业吃香技能TOP榜,欢迎补充
  16. 2019-7-2-WPF-通过-ReadyToRun-提升性能
  17. 4.25分享(贪心算法基础)
  18. ARP攻击,查找哪台电脑中病毒
  19. C70600白铜棒/90-10铜镍合金管Cu90Ni10铁白铜
  20. 使用frontpage下载整站

热门文章

  1. 【Kotlin】Kotlin 类的继承 三 ( super 关键字使用 | super@ 外部调用父类方法 | 子类选择性调用 父类 / 接口 方法 super )
  2. 【JetPack】ViewBinding 视图绑定组件 ( 启用模块 | 视图绑定定制 | 绑定类名称生成规则 | 绑定类字段生成规则 | 绑定类获取根视图 | 绑定类获取布局组件 )
  3. 【Android 应用开发】Android 返回堆栈管理 ( 默认启动模式 | 栈顶复用启动模式 | 栈内复用启动模式 | 单实例启动模式 | CLEAR_TOP 标识 )
  4. Subversion基本操作
  5. android-学习1 配置环境
  6. Windbg调试命令详解
  7. oracle编程艺术笔记1
  8. 课程名称翻译大全(zz)
  9. tar:file-changed-as-we-read-it报错处理
  10. cgroup 介绍 与使用