这一段时间用到了一个对一组类型的数据排序,由于golang没有提供类似c++中set的内置数据结构,这里需要对一个slice中的元素进行排序,由浅到深学习golang中的排序。
golang提供了一个名为sort
的包,里面提供了基础数据类型的排序:int
,float64
,string
,其他的类型,比如:int32
,int64
,float32
等并没有实现,但是只要使用者实现了sort包中Interface接口的三个函数就可以实现这些类型的排序,sort包中Interface的接口:
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
以一个int切片为例:
func test2() {
nums := []int{
8, 9, 1, 3, 5, 7, 11, 52, 2, -1}
show("origin", nums...)
// 调用sort包中的Ints函数排序
sort.Ints(nums)
show("inner", nums...)
}
结果:
其他的float64
,string
两种也是一样的,调用提供的函数即可排序。
我们以int64
为例,定义一个int64
的切片,对其排序。整体的思路就是定一个类型,实现sort中Interface接口的三个函数,完成int64类型的排序。
实现接口
type int64Slice []int64
func (p int64Slice) Len() int {
return len(p)
}
func (p int64Slice) Less(i, j int) bool {
return p[i] < p[j]
}
func (p int64Slice) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func main() {
// 定义一组int64的slice
i64 := []int64{
4, 5, 7, 8, 9, 0, 7, 65, 5, 4, 34, 3, 3}
fmt.Println("int64排序前:", i64)
sort.Sort(int64Slice(i64))
fmt.Println("int64排序后:", i64)
}
对于一些自定义的类型来说,也存在需要根据某些字段排序的可能性。我们以学生信息为例,对自定义的学生数据类型排序。
学生类型如下:
type Student struct {
Name string // 姓名
Age int32 // 年龄
Score float64 // 成绩
}
我们想通过不同的字段对一组学生排序,比如根据学生的姓名,学生的年龄或者学生的成绩排序,分为三部分实施:
定义一个函数,入参为*Student的两个变量,返回值为bool
,通过这个函数可以实现根据学生的多种信息对学生排序,实现如下:
type By func(p1, p2 *Student) bool
func (by By) SortStudent(name string, sutdents []Student) {
ss := &StudentSorter{
students: sutdents,
by: by,
}
// 调用sort包中的内置的排序方法
sort.Sort(ss)
// 自定义的打印排序后的切片内容
ss.Show(name)
}
在学生的排序实例里,我们要实现sort包的三个接口函数,然后通过将比较的类型的函数传递进去,就可以实现学生变量的排序,实现:
// 学生的排序对象
type StudentSorter struct {
students []Student
by func(p1, p2 *Student) bool
}
func (s *StudentSorter) Len() int {
return len(s.students)
}
func (s *StudentSorter) Less(i, j int) bool {
return s.by(&s.students[i], &s.students[j])
}
func (s *StudentSorter) Swap(i, j int) {
s.students[i], s.students[j] = s.students[j], s.students[i]
}
// 为了打印排序后的数据
func (s StudentSorter) Show(name string) {
fmt.Println(">> ", name)
for _, s := range s.students {
fmt.Printf("name=%v,age=%v, score=%v\n", s.Name, s.Age, s.Score)
}
}
在根据学生的信息排序时,要定义By
类型的比较函数,根据比较函数方可实现具体的排序,实现:
package main
func main() {
ss := []Student{
Student{
Name: "Andy", Age: 18, Score: 99.5},
Student{
Name: "Tim", Age: 78, Score: 90.5},
Student{
Name: "John", Age: 55, Score: 80.5},
Student{
Name: "Jam", Age: 32, Score: 49.5},
}
name := func(s1, s2 *Student) bool {
return s1.Name < s2.Name
}
// 成绩升序
score := func(s1, s2 *Student) bool {
return s1.Score < s2.Score
}
// 专门用了倒叙,排序后的年龄应该是降序
age := func(s1, s2 *Student) bool {
return s1.Age > s2.Age
}
By(name).SortStudent("按姓名排序", ss)
By(score).SortStudent("按成绩排序", ss)
By(age).SortStudent("按年龄排序", ss)
}