在程式開發中,不可避免的需要給資料集進行排序,如果在語言級别不提供支援的話,我們則需要自己寫算法進行資料的處理,麻煩還不一定高效。
幸好Golang在标準包中,官方有提供sort包中Sort()函數提供排序功能。并且天然支援[]int,[]float64,[]string切片的排序查找功能,并且也能夠實作對自定義類型集合的排序。
下面我們先來看下golang中Sort函數的結構是什麼樣的。
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}
可以看到,該函數接收的唯一的參數就是待排序集合,該集合應是一個Interface,而我們如果需要讓自定義類型的集合能夠被排序,則需要實作該interface以保證類型一緻。該接口中有三個方法:
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)
}
資料集合實作了這三個方法後,就可以使用該包的Sort()函數進行排序。
1.1讓我們來看一個以學生年齡排序的小案例:
type Stu []student
func main() {
var students = make(Stu, 0)
for i := 0; i < 10; i++ {
stu := student{
name: strconv.Itoa(i) + "~~",
age: i,
}
students = append(students, stu)
}
for _, item := range students {
fmt.Println(item.name, "--", item.age)
}
sort.Sort(students)
fmt.Println("is sorted? ", sort.IsSorted(students)) //可以檢測是否已經排序
for _, item := range students {
fmt.Println(item.name, "--", item.age)
}
}
func (s Stu) Len() int { //傳回集合的長度
return len(s)
}
//Less 被定義為:i 在 j前面為true;是以我們比較i < j 是否為 true,
//i < j = false,表示i放在後面,是以目前是降序
func (s Stu) Less(i, j int) bool { //用來決定是升序還是降序
return s[i].age > s[j].age
}
func (s Stu) Swap(i, j int) { //改變資料在集合中的位置
s[i], s[j] = s[j], s[i]
}
type student struct {
name string
age int
}
在Less方法中,我使用的是int類型的年齡來進行降序排列的,如果需要升序隻需要變成 < 号即可:
func (s Stu) Less(i, j int) bool {
return s[i].age < s[j].age
}
1.2最後再來個基本int型的使用案例
在sort包中,給[]int排序的方法是IntSlice,結構如下:
type IntSlice []int
func (p IntSlice) Len() int { return len(p) }
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
func (p IntSlice) Sort() { Sort(p) }
可以看到,該[]int也實作了Sort函數中的接口,并且有一個Sort()方法,是以我們可以這樣使用:
var nums = []int{1, 3, 2, 5, 3, 65, 3}
sort.IntSlice(nums).Sort()
如果我們不想這麼麻煩,sort包為我們提供了一個Ints方法,調用該方法可以直接排序:
var nums = []int{1, 3, 2, 5, 3, 65, 3}
sort.Ints(nums)
fmt.Println(nums)
輸出結果:
[1 2 3 3 3 5 65]
如果需要改變排序方式的話,包中同樣有提供一個Reverse方法:
func Reverse(data Interface) Interface {
return &reverse{data}
}
我們看到,Reverse函數跟Sort函數接收同樣的方法,是以我們的排序時需要使用實作了那三個方法的IntSlice方法,使用方式:
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
劇終!