[转]Golang’s solution to sorting custom types
原文:https://developpaper.com/golangs-solution-to-sorting-custom-types/
https://gobyexample.com/sorting-by-functions
Sometimes we’ll want to sort a collection by something other than its natural order. For example, suppose we wanted to sort strings by their length instead of alphabetically. Here’s an example of custom sorts in Go.
In order to sort by a custom function in Go, we need a corresponding type. Here we’ve created a byLength
type that is just an alias for the builtin []string
type.
We implement sort.Interface
- Len
, Less
, and Swap
- on our type so we can use the sort
package’s generic Sort
function. Len
and Swap
will usually be similar across types and Less
will hold the actual custom sorting logic. In our case we want to sort in order of increasing string length, so we use len(s[i])
and len(s[j])
here.
With all of this in place, we can now implement our custom sort by converting the original fruits
slice to byLength
, and then use sort.Sort
on that typed slice.
Running our program shows a list sorted by string length, as desired.
By following this same pattern of creating a custom type, implementing the three Interface
methods on that type, and then calling sort.Sort on a collection of that custom type, we can sort Go slices by arbitrary functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package main import ( "fmt" "sort" ) type byLength []string func (s byLength) Len() int { return len(s) } func (s byLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) } func main() { fruits := []string{ "peach" , "banana" , "kiwi" } sort.Sort(byLength(fruits)) fmt.Println(fruits) } |
--------------------------------
Preface
Go language supports our custom types. In actual projects, we often need to sort according to a certain field of a structure type. I didn’t know how to solve this problem before. Later, I searched the Internet for related problems and found some good solutions. Here is a summary.
Because the sort package of golang provides corresponding functions, we don’t need to build a wheel repeatedly. Let’s see how to use the sort package to realize it.
On sort package
The sort package of sorting algorithm is also implemented in golang. The sort package internally implements four basic sorting algorithms: insertion sort, symmerge, heap sort and quick sort. The sort package automatically selects the optimal sorting algorithm according to the actual data.
So when we write code, we only need to consider the implementationsort.Interface
This type is fine.
Take a rough look at the sort package
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | func Sort(data Interface) { // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached. n := data.Len() maxDepth := 0 for i := n; i > 0; i >>= 1 { maxDepth++ } maxDepth *= 2 quickSort(data, 0, n, maxDepth) } 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) } //Four sorting algorithms implemented internally //Insert sort func insertionSort(data Interface, a, b int) // heap sort func heapSort(data Interface, a, b int) //Quick sort func quickSort(data Interface, a, b, maxDepth int) //Merge sort func symMerge(data Interface, a, m, b int) |
So callsort.Sort()
To implement custom type sorting, we only need our type to implement three methods in the interface interface type.
First look at the sort package itself[]int
How to sort types
1 2 3 4 5 6 7 8 9 10 11 | //First, an alias of type [] int intslice is defined type IntSlice []int //Get the length of this slice func (p IntSlice) Len() int { return len(p) } //Compare two element sizes in ascending order func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] } //Exchange data func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } //Sort. Ints() calls the sort() method internally to implement sorting //Note that we need to convert [] int to intslice type first, because this type implements three methods of interface func Ints(a []int) { Sort(IntSlice(a)) } |
According to huluduapiao, we can sort the custom structure types in descending order
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package main import ( "fmt" "sort" ) type Person struct { Name string Age int } type Persons []Person //Get the length of this slice func (p Persons) Len() int { return len(p) } //Sort by the age of the element in descending order (write here according to your own business logic) func (p Persons) Less(i, j int) bool { return p[i].Age > p[j].Age } //Exchange data func (p Persons) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func main() { persons := Persons{ { Name: "test1" , Age: 20, }, { Name: "test2" , Age: 22, }, { Name: "test3" , Age: 21, }, } Fmt.println ( "before sorting" ) for _, person := range persons { fmt.Println(person.Name, ":" , person.Age) } sort.Sort(persons) Fmt.println ( "after sorting" ) for _, person := range persons { fmt.Println(person.Name, ":" , person.Age) } } |
In fact, generalLen()
andSwap()
Basically no change, only involving element comparisonLess()
The approach will change.
What should we do when sorting multiple fields in a certain structure? Do we write down these three methods for each sorting? Of course not. We can use nested structures to solve this problem. Because nested structures can inherit all the properties and methods of the parent structure
For example, if I want to sort the name field and age of the person above, we can use nested structure to improve it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | package main import ( "fmt" "sort" ) type Person struct { Name string Age int } type Persons []Person //The len () and swap () methods do not change //Get the length of this slice func (p Persons) Len() int { return len(p) } //Exchange data func (p Persons) Swap(i, j int) { p[i], p[j] = p[j], p[i] } //Nested structures inherit all properties and methods of person //So sortByName also implements len() and swap() methods type SortByName struct { Persons } //Sort by the name length of the element in descending order (write here according to your own business logic) func (p SortByName) Less(i, j int) bool { return len(p.Persons[i].Name) > len(p.Persons[j].Name) } type SortByAge struct { Persons } //Sort by the age of the element in descending order (write here according to your own business logic) func (p SortByAge) Less(i, j int) bool { return p.Persons[i].Age > p.Persons[j].Age } func main() { persons := Persons{ { Name: "test123" , Age: 20, }, { Name: "test1" , Age: 22, }, { Name: "test12" , Age: 21, }, } Fmt.println ( "before sorting" ) for _, person := range persons { fmt.Println(person.Name, ":" , person.Age) } sort.Sort(SortByName{persons}) Fmt.println ( "after sorting" ) for _, person := range persons { fmt.Println(person.Name, ":" , person.Age) } } |
summary
The above is the whole content of this article. I hope that the content of this article has a certain reference learning value for everyone’s study or work. If you have any questions, you can leave a message and exchange. Thank you for your support for developepaar.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
2017-01-18 linux shell操作
2017-01-18 linux用户管理
2015-01-18 Namespacing in PHP (php 中使用命名空间)