当前位置:首页 > 文章列表 > Golang > Go教程 > Go语言排序(借助sort.Interface接口)

Go语言排序(借助sort.Interface接口)

来源:云海天教程 2022-12-28 13:12:51 0浏览 收藏

怎么入门Golang编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《Go语言排序(借助sort.Interface接口)》,涉及到接口,有需要的可以收藏一下

排序操作和字符串格式化一样是很多程序经常使用的操作。尽管一个最短的快排程序只要 15 行就可以搞定,但是一个健壮的实现需要更多的代码,并且我们不希望每次我们需要的时候都重写或者拷贝这些代码。

幸运的是,sort 包内置的提供了根据一些排序函数来对任何序列排序的功能。它的设计非常独到。在很多语言中,排序算法都是和序列数据类型关联,同时排序函数和具体类型元素关联。

相比之下,Go语言的 sort.Sort 函数不会对具体的序列和它的元素做任何假设。相反,它使用了一个接口类型 sort.Interface 来指定通用的排序算法和可能被排序到的序列类型之间的约定。这个接口的实现由序列的具体表示和它希望排序的元素决定,序列的表示经常是一个切片。

一个内置的排序算法需要知道三个东西:序列的长度,表示两个元素比较的结果,一种交换两个元素的方式;这就是 sort.Interface 的三个方法:

package sorttype Interface interface { Len() int // 获取元素数量 Less(i, j int) bool // i,j是序列元素的指数。 Swap(i, j int) // 交换元素}为了对序列进行排序,我们需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用 sort.Sort 函数。思考对一个字符串切片进行排序,这可能是最简单的例子了。下面是这个新的类型 MyStringList 和它的 Len,Less 和 Swap 方法

type MyStringList []stringfunc (p MyStringList ) Len() int { return len(m) }func (p MyStringList ) Less(i, j int) bool { return m[i]

使用sort.Interface接口进行排序

对一系列字符串进行排序时,使用字符串切片([]string)承载多个字符串。使用 type 关键字,将字符串切片([]string)定义为自定义类型 MyStringList。为了让 sort 包能识别 MyStringList,能够对 MyStringList 进行排序,就必须让 MyStringList 实现 sort.Interface 接口。

下面是对字符串排序的详细代码(代码1):

package mainimport ( "fmt" "sort")// 将[]string定义为MyStringList类型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] 代码输出结果:
1. First Blood
2. Double Kill
3. Triple Kill
4. Quadra Kill
5. Penta Kill

代码说明如下:第 9 行,接口实现不受限于结构体,任何类型都可以实现接口。要排序的字符串切片 []string 是系统定制好的类型,无法让这个类型去实现 sort.Interface 排序接口。因此,需要将 []string 定义为自定义的类型。第 12 行,实现获取元素数量的 Len() 方法,返回字符串切片的元素数量。第 17 行,实现比较元素的 Less() 方法,直接取 m 切片的 i 和 j 元素值进行小于比较,并返回比较结果。第 22 行,实现交换元素的 Swap() 方法,这里使用 Go语言的多变量赋值特性实现元素交换。第 29 行,由于将 []string 定义成 MyStringList 类型,字符串切片初始化的过程等效于下面的写法:

names := []string { "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood",}第 38 行,使用 sort 包的 Sort() 函数,将 names(MyStringList类型)进行排序。排序时,sort 包会通过 MyStringList 实现的 Len()、Less()、Swap() 这 3 个方法进行数据获取和修改。第 41 行,遍历排序好的字符串切片,并打印结果。

常见类型的便捷排序

通过实现 sort.Interface 接口的排序过程具有很强的可定制性,可以根据被排序对象比较复杂的特性进行定制。例如,需要多种排序逻辑的需求就适合使用 sort.Interface 接口进行排序。但大部分情况中,只需要对字符串、整型等进行快速排序。Go语言中提供了一些固定模式的封装以方便开发者迅速对内容进行排序。

1) 字符串切片的便捷排序

sort 包中有一个 StringSlice 类型,定义如下:

type StringSlice []stringfunc (p StringSlice) Len() int { return len(p) }func (p StringSlice) Less(i, j int) bool { return p[i] sort 包中的 StringSlice 的代码与 MyStringList 的实现代码几乎一样。因此,只需要使用 sort 包的 StringSlice 就可以更简单快速地进行字符串排序。将代码1中的排序代码简化后如下所示:

names := sort.StringSlice{ "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood",}sort.Sort(names)简化后,只要两句代码就实现了字符串排序的功能。

2) 对整型切片进行排序

除了字符串可以使用 sort 包进行便捷排序外,还可以使用 sort.IntSlice 进行整型切片的排序。sort.IntSlice 的定义如下:

type IntSlice []intfunc (p IntSlice) Len() int { return len(p) }func (p IntSlice) Less(i, j int) bool { return p[i] sort 包在 sort.Interface 对各类型的封装上还有更进一步的简化,下面使用 sort.Strings 继续对代码1进行简化,代码如下:

names := []string{ "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood",}sort.Strings(names)// 遍历打印结果for _, v := range names { fmt.Printf("%s", v)}代码说明如下:第 1 行,需要排序的字符串切片。第 9 行,使用 sort.Strings 直接对字符串切片进行排序。

3) sort包内建的类型排序接口一览

Go语言中的 sort 包中定义了一些常见类型的排序方法,如下表所示。

sort 包中内建的类型排序接口类 型实现 sort.lnterface 的类型直接排序方法说 明字符串(String)StringSlicesort.Strings(a [] string)字符 ASCII 值升序整型(int)IntSlicesort.Ints(a []int)数值升序双精度浮点(float64)Float64Slicesort.Float64s(a []float64)数值升序
编程中经常用到的 int32、int64、float32、bool 类型并没有由 sort 包实现,使用时依然需要开发者自己编写。

对结构体数据进行排序

除了基本类型的排序,也可以对结构体进行排序。结构体比基本类型更为复杂,排序时不能像数值和字符串一样拥有一些固定的单一原则。结构体的多个字段在排序中可能会存在多种排序的规则,例如,结构体中的名字按字母升序排列,数值按从小到大的顺序排序。一般在多种规则同时存在时,需要确定规则的优先度,如先按名字排序,再按年龄排序等。

1) 完整实现sort.Interface进行结构体排序

将一批英雄名单使用结构体定义,英雄名单的结构体中定义了英雄的名字和分类。排序时要求按照英雄的分类进行排序,相同分类的情况下按名字进行排序,详细代码实现过程如下。

结构体排序代码(代码2):

package mainimport ( "fmt" "sort")// 声明英雄的分类type HeroKind int// 定义HeroKind常量, 类似于枚举const ( None HeroKind = iota Tank Assassin Mage)// 定义英雄名单的结构type Hero struct { Name string // 英雄的名字 Kind HeroKind // 英雄的种类}// 将英雄指针的切片定义为Heros类型type Heros []*Hero// 实现sort.Interface接口取元素数量方法func (s Heros) Len() int { return len(s)}// 实现sort.Interface接口比较元素方法func (s Heros) Less(i, j int) bool { // 如果英雄的分类不一致时, 优先对分类进行排序 if s[i].Kind != s[j].Kind { return s[i].Kind 代码输出如下:
&{Name:关羽 Kind:1}
&{Name:吕布 Kind:1}
&{Name:李白 Kind:2}
&{Name:貂蝉 Kind:2}
&{Name:妲己 Kind:3}
&{Name:诸葛亮 Kind:3}

代码说明如下:第 9 行,将 int 声明为 HeroKind 英雄类型,后面会将这个类型当做枚举来使用。第 13 行,定义一些英雄类型常量,可以理解为枚举的值。第 26 行,为了方便实现 sort.Interface 接口,将 []*Hero 定义为 Heros 类型。第 29 行,Heros 类型实现了 sort.Interface 的 Len() 方法,返回英雄的数量。第 34 行,Heros 类型实现了 sort.Interface 的 Less() 方法,根据英雄字段的比较结果决定如何排序。第 37 行,当英雄的分类不一致时,优先按分类的枚举数值从小到大排序。第 42 行,英雄分类相等的情况下,默认根据英雄的名字字符升序排序。第 46 行,Heros 类型实现了 sort.Interface 的 Swap() 方法,交换英雄元素的位置。第 53~60 行,准备一系列英雄数据。第 63 行,使用 sort 包进行排序。第 66 行,遍历所有排序完成的英雄数据。

2) 使用sort.Slice进行切片元素排序

从 Go 1.8 开始,Go语言在 sort 包中提供了 sort.Slice() 函数进行更为简便的排序方法。sort.Slice() 函数只要求传入需要排序的数据,以及一个排序时对元素的回调函数,类型为 func(i,j int)bool,sort.Slice() 函数的定义如下:

func Slice(slice interface{}, less func(i, j int) bool)使用 sort.Slice() 函数,对代码2重新优化的完整代码如下:

package mainimport ( "fmt" "sort")type HeroKind intconst ( None = iota Tank Assassin Mage)type Hero struct { Name string Kind HeroKind}func main() { heros := []*Hero{ {"吕布", Tank}, {"李白", Assassin}, {"妲己", Mage}, {"貂蝉", Assassin}, {"关羽", Tank}, {"诸葛亮", Mage}, } sort.Slice(heros, func(i, j int) bool { if heros[i].Kind != heros[j].Kind { return heros[i].Kind 第 33 行到第 39 行加粗部分是新添加的 sort.Slice() 及回调函数部分。对比前面的代码,这里去掉了 Heros 及接口实现部分的代码。

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

本篇关于《Go语言排序(借助sort.Interface接口)》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

版本声明
本文转载于:云海天教程 如有侵犯,请联系study_golang@163.com删除
Go语言接口的嵌套组合Go语言接口的嵌套组合
上一篇
Go语言接口的嵌套组合
Go语言实现日志系统(支持多种输出方式)
下一篇
Go语言实现日志系统(支持多种输出方式)
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
    笔灵AI生成答辩PPT
    探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
    16次使用
  • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
    知网AIGC检测服务系统
    知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
    24次使用
  • AIGC检测服务:AIbiye助力确保论文原创性
    AIGC检测-Aibiye
    AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
    30次使用
  • 易笔AI论文平台:快速生成高质量学术论文的利器
    易笔AI论文
    易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
    42次使用
  • 笔启AI论文写作平台:多类型论文生成与多语言支持
    笔启AI论文写作平台
    笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
    35次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码