sort包包含了切片排序和用户自定义数据集的相关函数,主要功能如下
- 计算长度
- 比较两个下标对应值的大小
- 排序
- 根据不同key值排序
- 多key值组合排序
- 排序的包装模式
- IsSorted 检查对象是否已经被排过序
- Reverse 反向排列
计算整数切片的长度
func (p IntSlice) Len() int
import (
"sort"
"fmt"
)
func main() {
list := sort.IntSlice{1,2,3,4,5,6}
fmt.Println(list.Len())
}
比较两个索引对应值的大小
func (p IntSlice) Less(i, j int) bool
i对应的值是否小于j对应的值
package main
import (
"sort"
"fmt"
)
func main() {
list := sort.IntSlice{1,2,3,4,5,6}
fmt.Println(list.Less(1,2))
}
排序
数组要实现排序,需要实现下面的接口
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)
}
下面看一下示例
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// ByAge 给[]Person 实现了 sort.Interface 接口
// 数组使用排序算法需要实现下面三个方法
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func Example() {
people := []Person{
{"a", 1},
{"b", 3},
{"c", 4},
{"d", 2},
}
fmt.Println(people)
//进行排序
sort.Sort(ByAge(people))
fmt.Println(people)
}
func main() {
Example()
}
以上我们就完成了对person 数组按照age从小到大的排序
根据不同key值排序
如果我们想要实现多种排序方式,比如上面的例子,我们有时需要按照年龄排序,有时需要按照姓名排序该如何实现呢?
方法1 让数组动态绑定排序方法Less(i, j int) bool
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// ByAge 给[]Person 实现了 sort.Interface 接口
// 数组使用排序算法需要实现下面三个方法
type personsSort struct {
Persons []Person
by func (Person,Person)bool
}
func (a personsSort) Len() int { return len(a.Persons) }
func (a personsSort) Swap(i, j int) { a.Persons[i], a.Persons[j] = a.Persons[j], a.Persons[i] }
func (a personsSort) Less(i, j int) bool { return a.by(a.Persons[i],a.Persons[j]) }
// 定义一个动态排序方法
type By func(Person,Person)bool
func (by By)Sort(perons []Person){
personsSort := &personsSort{
Persons:perons,
by:by,
}
sort.Sort(personsSort)
}
func Example() {
peoples := []Person{
{"b", 1},
{"a", 3},
{"c", 4},
{"d", 2},
}
// 按照名字排序
name := func (p1,p2 Person)bool{
return p1.Name < p2.Name
}
// 按照
age := func(p1,p2 Person) bool{
return p1.Age < p2.Age
}
By(name).Sort(peoples)
fmt.Println(peoples)
By(age).Sort(peoples)
fmt.Println(peoples)
}
func main() {
Example()
}
多key值组合排序
有的时候,我们需要对用户的姓名先排序,然后在按照姓名去排序,再用其他字段去排序,那么对于这样的需求我们该如何实现呢?
package main
import (
"fmt"
"sort"
)
func main() {
Example_sortMultiKeys()
}
// 第一步创建一个对象结构体
type User struct {
name string
age int
address string
}
// 定义筛选类型
type lessFunc func(p1, p2 *User) bool
// 第二步 构造一个能够执行多个key值筛选的结构体
type multiSorter struct {
user []User
less []lessFunc
}
// 第三步 创建多筛选对象
func OrderedBy(less ...lessFunc) *multiSorter {
return &multiSorter{
less: less,
}
}
// 第四步 实现sort.interface 接口
func (ms *multiSorter) Len() int {
return len(ms.user)
}
func (ms *multiSorter) Swap(i, j int) {
ms.user[i], ms.user[j] = ms.user[j], ms.user[i]
}
func (ms *multiSorter) Less(i, j int) bool {
p, q := &ms.user[i], &ms.user[j]
var k int
// 按照删选算法的顺序进行比较,如果两个值相等,则使用下一个筛选算法进行比较,如果算法只有一个,则不执行for 直接执行这个算法
for k = 0; k < len(ms.less)-1; k++ {
less := ms.less[k]
switch {
case less(p, q):
return true
case less(q, p):
return false
}
}
return ms.less[k](p, q)
}
// 第五步 实现排序算法
func (ms *multiSorter) Sort(changes []User) {
ms.user = changes
sort.Sort(ms)
}
var changes = []User{
{name:"a",age:12,address:"yunnan"},
{name:"a",age:13,address:"yunnan"},
{name:"a",age:13,address:"fujian"},
{name:"d",age:15,address:"shangxi"},
}
func Example_sortMultiKeys() {
name := func(c1, c2 *User) bool {
return c1.name < c2.name
}
age := func(c1, c2 *User) bool {
return c1.age < c2.age
}
address := func(c1, c2 *User) bool {
return c1.address < c2.address
}
OrderedBy(name).Sort(changes)
fmt.Println("By name:", changes)
OrderedBy(name,age).Sort(changes)
fmt.Println("By name,age", changes)
OrderedBy(name, age, address).Sort(changes)
fmt.Println("By name,age,address", changes)
}
排序的包装模式
在对于按照多种选择的排序的形式比如有时需要按照名称 有时需要按照年龄,这样的排序需求,我们也可以通过包装模式进行设计
package main
import (
"sort"
"fmt"
)
func main() {
Example_sortMultiKeys()
}
// 第一步创建一个对象结构体
type User struct {
name string
age int
address string
}
type Users []User
func (users Users)Len() int{
return len(users)
}
func (users Users)Swap(i,j int){
users[i],users[j] = users[j],users[i]
}
// 包装按照姓名排序
type ByName struct {
Users
}
func (byName ByName)Less(i,j int)bool{
return byName.Users[i].name < byName.Users[j].name
}
// 包装按照年龄排序
type ByAge struct {
Users
}
func (byAge ByAge)Less(i,j int)bool{
return byAge.Users[i].age < byAge.Users[j].age
}
var changes = []User{
{name:"a",age:12,address:"yunnan"},
{name:"d",age:15,address:"shangxi"},
{name:"a",age:14,address:"yunnan"},
{name:"a",age:13,address:"fujian"},
}
func Example_sortMultiKeys() {
sort.Sort(ByName{changes})
fmt.Println("by name:",changes)
sort.Sort(ByAge{changes})
fmt.Println("by age:",changes)
}
检查数组是否已经执行排序
func IsSorted(data Interface) bool
func Example_sortMultiKeys() {
fmt.Println(sort.IsSorted(ByName{changes}))
sort.Sort(ByName{changes})
fmt.Println("by name:",changes)
fmt.Println(sort.IsSorted(ByName{changes}))
}
反向排序
func Reverse(data Interface) Interface
Reverse包装一个Interface接口并返回一个新的Interface接口,对该接口排序可生成递减序列
func Example_sortMultiKeys() {
sort.Sort(ByName{changes})
fmt.Println("by name:",changes)
sort.Sort(sort.Reverse(ByName{changes}))
fmt.Println("by name:",changes)
}