package sort type Interface interface { Len() int // 获取元素数量 Less(i, j int) bool // i,j是序列元素的指数。 Swap(i, j int) // 交换元素 }为了对序列进行排序,我们需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用 sort.Sort 函数。思考对一个字符串切片进行排序,这可能是最简单的例子了。下面是这个新的类型 MyStringList 和它的 Len,Less 和 Swap 方法
type MyStringList []string func (p MyStringList ) Len() int { return len(m) } func (p MyStringList ) Less(i, j int) bool { return m[i] < m[j] } func (p MyStringList ) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
package main import ( "fmt" "sort" ) // 将[]string定义为MyStringList类型 type MyStringList []string // 实现sort.Interface接口的获取元素数量方法 func (m MyStringList) Len() int { return len(m) } // 实现sort.Interface接口的比较元素方法 func (m MyStringList) Less(i, j int) bool { return m[i] < m[j] } // 实现sort.Interface接口的交换元素方法 func (m MyStringList) Swap(i, j int) { m[i], m[j] = m[j], m[i] } func main() { // 准备一个内容被打乱顺序的字符串切片 names := MyStringList{ "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood", } // 使用sort包进行排序 sort.Sort(names) // 遍历打印结果 for _, v := range names { fmt.Printf("%s\n", v) } }代码输出结果:
1. First Blood
2. Double Kill
3. Triple Kill
4. Quadra Kill
5. Penta Kill
names := []string { "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood", }
type StringSlice []string func (p StringSlice) Len() int { return len(p) } func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] } func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // Sort is a convenience method. func (p StringSlice) Sort() { Sort(p) }sort 包中的 StringSlice 的代码与 MyStringList 的实现代码几乎一样。因此,只需要使用 sort 包的 StringSlice 就可以更简单快速地进行字符串排序。将代码1中的排序代码简化后如下所示:
names := sort.StringSlice{ "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood", } sort.Sort(names)简化后,只要两句代码就实现了字符串排序的功能。
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) }sort 包在 sort.Interface 对各类型的封装上还有更进一步的简化,下面使用 sort.Strings 继续对代码1进行简化,代码如下:
names := []string{ "3. Triple Kill", "5. Penta Kill", "2. Double Kill", "4. Quadra Kill", "1. First Blood", } sort.Strings(names) // 遍历打印结果 for _, v := range names { fmt.Printf("%s\n", v) }代码说明如下:
类 型 | 实现 sort.lnterface 的类型 | 直接排序方法 | 说 明 |
---|---|---|---|
字符串(String) | StringSlice | sort.Strings(a [] string) | 字符 ASCII 值升序 |
整型(int) | IntSlice | sort.Ints(a []int) | 数值升序 |
双精度浮点(float64) | Float64Slice | sort.Float64s(a []float64) | 数值升序 |
package main import ( "fmt" "sort" ) // 声明英雄的分类 type HeroKind int // 定义HeroKind常量, 类似于枚举 const ( None HeroKind = iota Tank Assassin Mage ) // 定义英雄名单的结构 type Hero struct { Name string // 英雄的名字 Kind HeroKind // 英雄的种类 } // 将英雄指针的切片定义为Heros类型 type Heros []*Hero // 实现sort.Interface接口取元素数量方法 func (s Heros) Len() int { return len(s) } // 实现sort.Interface接口比较元素方法 func (s Heros) Less(i, j int) bool { // 如果英雄的分类不一致时, 优先对分类进行排序 if s[i].Kind != s[j].Kind { return s[i].Kind < s[j].Kind } // 默认按英雄名字字符升序排列 return s[i].Name < s[j].Name } // 实现sort.Interface接口交换元素方法 func (s Heros) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func main() { // 准备英雄列表 heros := Heros{ &Hero{"吕布", Tank}, &Hero{"李白", Assassin}, &Hero{"妲己", Mage}, &Hero{"貂蝉", Assassin}, &Hero{"关羽", Tank}, &Hero{"诸葛亮", Mage}, } // 使用sort包进行排序 sort.Sort(heros) // 遍历英雄列表打印排序结果 for _, v := range heros { fmt.Printf("%+v\n", v) } }代码输出如下:
&{Name:关羽 Kind:1}
&{Name:吕布 Kind:1}
&{Name:李白 Kind:2}
&{Name:貂蝉 Kind:2}
&{Name:妲己 Kind:3}
&{Name:诸葛亮 Kind:3}
func Slice(slice interface{}, less func(i, j int) bool)使用 sort.Slice() 函数,对代码2重新优化的完整代码如下:
package main import ( "fmt" "sort" ) type HeroKind int const ( None = iota Tank Assassin Mage ) type Hero struct { Name string Kind HeroKind } func main() { heros := []*Hero{ {"吕布", Tank}, {"李白", Assassin}, {"妲己", Mage}, {"貂蝉", Assassin}, {"关羽", Tank}, {"诸葛亮", Mage}, } sort.Slice(heros, func(i, j int) bool { if heros[i].Kind != heros[j].Kind { return heros[i].Kind < heros[j].Kind } return heros[i].Name < heros[j].Name }) for _, v := range heros { fmt.Printf("%+v\n", v) } }第 33 行到第 39 行加粗部分是新添加的 sort.Slice() 及回调函数部分。对比前面的代码,这里去掉了 Heros 及接口实现部分的代码。
Copyright © 广州京杭网络科技有限公司 2005-2025 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有