最近用 sort.Slice 方法对 slice 做排序功能的时候遇到了一个小坑
先看一段代码
package main
import (
"fmt"
"sort"
)
func main() {
people := []struct {
Name string
Age int
}{
{"Alice", 25},
{"Elizabeth", 75},
{"Alice", 75},
{"Bob", 75},
{"Alice", 75},
{"Bob", 25},
{"Colin", 25},
{"Elizabeth", 25},
}
sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
fmt.Println("By name:", people)
sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
fmt.Println("By age:", people)
}
输出
By name: [{Alice 25} {Alice 75} {Alice 75} {Bob 75} {Bob 25} {Colin 25} {Elizabeth 75} {Elizabeth 25}]
By age: [{Alice 25} {Elizabeth 25} {Bob 25} {Colin 25} {Alice 75} {Bob 75} {Elizabeth 75} {Alice 75}]
有没有注意到一个点,按照 Age 排序的地方,相等的元素老的切片中的顺序变了,一般情况下,这种情况没什么影响,但是如果业务需求对顺序有强要求的话,这就有问题了。
解决方案,用 sort.SliceStable 方法,sort.SliceStable 可以保持元素顺序和之前切片中的一样。
SliceStable sorts the provided slice given the provided less function > > while keeping the original order of equal elements.
The function panics if the provided interface is not a slice.
新的代码如下
package main
import (
"fmt"
"sort"
)
func main() {
people := []struct {
Name string
Age int
}{
{"Alice", 25},
{"Elizabeth", 75},
{"Alice", 75},
{"Bob", 75},
{"Alice", 75},
{"Bob", 25},
{"Colin", 25},
{"Elizabeth", 25},
}
// Sort by name, preserving original order
sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })
fmt.Println("By name:", people)
// Sort by age preserving name order
sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })
fmt.Println("By age,name:", people)
}
这次的结果,按照 Age 排序,相等的元素依然保持着和之前一样的排序
By name: [{Alice 25} {Alice 75} {Alice 75} {Bob 75} {Bob 25} {Colin 25} {Elizabeth 75} {Elizabeth 25}]
By age,name: [{Alice 25} {Bob 25} {Colin 25} {Elizabeth 25} {Alice 75} {Alice 75} {Bob 75} {Elizabeth 75}]
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号