一起学go开发:数组排序
数组作为一种常见的数据结构,在实际工作中对数组的排序应用场景非常普遍,无论是php、java、还是今天要说的go,每一种语言都有其特定的实现方式。
我们学习过go语言的标准包和array的用法,我们或许已经知道,可以使用sort.Ints和sort.Slice函数进行排序,但是这个函数只能对纯数字形式的切片进行升序操作。
var a = []int{1, 3, 2, 5, 4} sort.Ints(a) fmt.Println(a)
现在有一份学生的成绩单,使用的是数组(或切片)形式,记录了学生的姓名:Name和考试成绩Score,需要对这份成绩单进行排序,该怎么实现呢?先来看看这份成绩单的数据结构:
type Score struct { name string score int }
我们要实现的是将StuScore按照score的大小进行升序、降序的排序。
我们先分析sort.Ints函数是如何实现对纯数字形式的切片进行排序的,Ints函数的源码如下:
// Ints sorts a slice of ints in increasing order. func Ints(x []int) { Sort(IntSlice(x)) }
初看觉得很简单,对不对?让我们认真的对待这段代码:
x是我们需要进行排序的切片,x先经过IntSlice类型的处理,后由Sort函数处理,注意:Sort的入参是一个Interface。
先来看IntSlice的源码:
// IntSlice attaches the methods of Interface to []int, sorting in increasing order. type IntSlice []int func (x IntSlice) Len() int { return len(x) } func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] } func (x IntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
从IntSlice源码的注释里,我们得知,IntSlice做的事情是:把Interface的方法加入到x切片。Interface是哪个Interface?Interface有哪几个方法?Interface通常就是本包里定义的Interface,所以我们可以很容易就定位到Interface的源码,如下:
type Interface interface { Len() int Less(i int, j int) bool Swap(i int, j int) }
这个Interface也就是Sort函数要处理的。
看到这里,我们会有一个疑问:为什么x不直接交给Sort处理,而要先经过IntSlice处理再由Sort处理?
这样做的目的是,让x具备Len、Less、Swap这三个接口定义的方法签名,以便于交给Sort进行排序,未实现这三个方法签名的切片不具备排序的能力。
既然知道了切片实现排序的基本原理,把我们的成绩单转换为可排序的切片,就可以实现对成绩单进行升序、降序的排序操作了。
实现步骤:
第一步:定义成绩单模型Score,并为成绩单实现Len、Less、Swap这三个方法
// Desc false默认升序,true为降序 var Desc bool type Score struct { name string score int } type Scores []Score func (s Scores) Len() int { return len(s) } func (s Scores) Less(i, j int) bool { if Desc { return s[i].score > s[j].score } return s[i].score < s[j].score } func (s Scores) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
第二步:模拟学生成绩单
// SchoolReport 成绩单 func SchoolReport() { scores := Scores{ {"alan", 95}, {"hikerell", 91}, {"acmfly", 96}, {"leao", 90}, } fmt.Println("Default:\n\t", scores) sort.Sort(scores) fmt.Println("IS Sorted?\n\t", sort.IsSorted(scores)) fmt.Println("Sorted:\n\t", scores) }
第三步:分别调用升序函数、降序函数,实现对成绩单的排序操作
student.SchoolReport() student.Desc = true student.SchoolReport()
除了以上的排序方式外,还可以使用sort.Slice实现排序,代码如下:
var desc bool people :=[]struct{ Name string Age int }{ {"Gopher", 7}, {"Alice", 55}, {"Vera", 24}, {"Bob", 75}, } desc = true sort.Slice(people, func(i, j int) bool { if desc { return people[i].Age > people[j].Age } return people[i].Age < people[j].Age }) fmt.Println("Sort by age:\n", people)