排序是开发中不可避免的,go的标准库sort提供了这一功能,主要针对[]int[]float64[]string、以及其他自定义切片的排序。对于前三个切片基本没有可说的,而对于用户自定义切片,就需要我们自己去实现它的排序了,实现Interface接口再调用sort.Sort()

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type NewInt []int

func (n NewInt) Len() int {
return len(n)
}

func (n NewInt) Less(i, j int) bool {
return n[i] < n[j]
}

func (n NewInt) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
}

func main() {
n := []int{1,3,2}
sort.Sort(NewInt(n))
fmt.Println(n)
}

这样写虽然规范,但是略微繁琐,大多时候我更希望简单一点,使用sort.Slice可以简化上述代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func main() {
people := []struct {
Name string
Age int
}{
{"Gopher", 18},
{"Alice", 20},
{"Vera", 24},
{"Bob", 18},
}
// 按年龄降序排序
sort.Slice(people, func(i, j int) bool {
return people[i].Age > people[j].Age
})
fmt.Println("Sort by age:", people)
}

这样的好处是简化了许多内容,但是不易于后期维护。

  上述方式实现了一个对结构体单字段的排序,核心在于自定义函数Lees(),思考一下,我们能否实现一个基于多字段的排序呢,类似于mysql的order by。当然是可以的,实现起来也很简单,当第一个排序索引相同时对第二个排序索引进行排序即可,示例如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func main() {
people := []struct {
Name string
Age int
}{
{"Gopher", 18},
{"Alice", 20},
{"Vera", 24},
{"Bob", 18},
}
// 按年龄降序排序,年龄相同的按姓名
sort.Slice(people, func(i, j int) bool {
if people[i].Age == people[j].Age {
return people[i].Name < people[j].Name
}
return people[i].Age > people[j].Age
})
fmt.Println("Sort by age and name:", people)
}