好好爱自己!

[转]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 - LenLess, 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.

 

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.InterfaceThis type is fine.

Take a rough look at the sort package

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

//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

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.

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.

posted @ 2022-01-18 20:18  立志做一个好的程序员  阅读(71)  评论(0编辑  收藏  举报

不断学习创作,与自己快乐相处