4

Golang 的排序和透過函數自訂排序

 2 years ago
source link: https://calvertyang.github.io/2021/09/16/golang-sorting-and-custom-sorting-by-functions/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

原文:CalliCoderGolang Sorting and Custom Sorting by functions

排序是我們平常撰寫程式時常見的用法。在本文中,你將學到如何在 Go 中對原始類型(string、int、float64)和自訂的集合進行排序。

在 Go 中對字串、整數或浮點數的 slice 進行排序

Go 的 sort package 提供了幾種方便的方法來對原始類型的 slice 進行排序。以下範例示範了如何在 Go 中對字串、整數和浮點數的 slice 進行排序:

package main

import (
	"fmt"
	"sort"
)

func main() {
	// Sorting a slice of Strings
	strs := []string{"quick", "brown", "fox", "jumps"}
	sort.Strings(strs)
	fmt.Println("Sorted strings: ", strs)

	// Sorting a slice of Integers
	ints := []int{56, 19, 78, 67, 14, 25}
	sort.Ints(ints)
	fmt.Println("Sorted integers: ", ints)

	// Sorting a slice of Floats
	floats := []float64{176.8, 19.5, 20.8, 57.4}
	sort.Float64s(floats)
	fmt.Println("Sorted floats: ", floats)
}
$ go run sorting.go
Sorted strings:  [brown fox jumps quick]
Sorted integers:  [14 19 25 56 67 78]
Sorted floats:  [19.5 20.8 57.4 176.8]

以相反順序對 slice 進行排序

要以相反順序對 slice 進行排序,你可以在 StringSliceIntSliceFloat64Slice 類型上使用 Reverse() 函數。這些類型實作了 sort package 中定義用來比較和交換的 Interface

Reverse() 函數返回了相反順序的資料。讓我們來看一個以相反順序對字串、整數和浮點數的 slice 進行排序的範例:

package main

import (
	"fmt"
	"sort"
)

func main() {
	// Sorting a slice of Strings
	strs := []string{"quick", "brown", "fox", "jumps"}
	sort.Sort(sort.Reverse(sort.StringSlice(strs)))
	fmt.Println("Sorted strings in reverse order: ", strs)

	// Sorting a slice of Integers
	ints := []int{56, 19, 78, 67, 14, 25}
	sort.Sort(sort.Reverse(sort.IntSlice(ints)))
	fmt.Println("Sorted integers in reverse order: ", ints)

	// Sorting a slice of Floats
	floats := []float64{176.8, 19.5, 20.8, 57.4}
	sort.Sort(sort.Reverse(sort.Float64Slice(floats)))
	fmt.Println("Sorted floats in reverse order: ", floats)
}
$ go run reverse-sorting.go
Sorted strings in reverse order:  [quick jumps fox brown]
Sorted integers in reverse order:  [78 67 56 25 19 14]
Sorted floats in reverse order:  [176.8 57.4 20.8 19.5]

在 Go 中使用比較器函數對 slice 進行排序

很多時候,你可能希望按照自然順序以外的方式對集合進行排序。例如,你想按照長度對字串 slice 進行排序,或者按照年齡對使用者進行排序。

對於這些案例,你可以使用 sort package 提供的 Slice()SliceStable() 函數。這些是能接受 less 函數作為參數的高階函數:

func Slice(x interface{}, less func(i, j int) bool)
func SliceStable(x interface{}, less func(i, j int) bool)

less 函數是一個比較器函數,它回報索引 i 處的元素是否應該排在索引 j 處的元素前。如果 less(i, j)less(j, i) 都是返回 false,那麼索引 ij 處的元素被視為是相同的。

當使用 Slice() 函數時,排序不保證穩定:相等的元素可能會和它們原本的順序顛倒。要穩定的排序,請使用 SliceStable()

讓我們來看個範例:

package main

import (
	"fmt"
	"sort"
)

func main() {
	// Sorting a slice of strings by length
	strs := []string{"United States", "India", "France", "United Kingdom", "Spain"}
	sort.Slice(strs, func(i, j int) bool {
		return len(strs[i]) < len(strs[j])
	})
	fmt.Println("Sorted strings by length: ", strs)

	// Stable sort
	sort.SliceStable(strs, func(i, j int) bool {
		return len(strs[i]) < len(strs[j])
	})
	fmt.Println("[Stable] Sorted strings by length: ", strs)

	// Sorting a slice of strings in the reverse order of length
	sort.SliceStable(strs, func(i, j int) bool {
		return len(strs[j]) < len(strs[i])
	})
	fmt.Println("[Stable] Sorted strings by reverse order of length: ", strs)
}
$ go run sorting-by-comparator.go
Sorted strings by length:  [India Spain France United States United Kingdom]
[Stable] Sorted strings by length:  [India Spain France United States United Kingdom]
[Stable] Sorted strings by reverse order of length:  [United Kingdom United States France India Spain]

在 Go 中使用比較器函數對 struce slice 進行排序

延續上一個範例,此範例將示範如何透過將自訂的 less 函數傳遞給 Slice()SliceStable() 函數,來對使用者自訂的 struct 進行排序:

package main

import (
	"fmt"
	"sort"
)

type User struct {
	Name string
	Age  int
}

func main() {
	// Sorting a slice of structs by a field
	users := []User{
		{
			Name: "Rajeev",
			Age:  28,
		},
		{
			Name: "Monica",
			Age:  31,
		},
		{
			Name: "John",
			Age:  56,
		},
		{
			Name: "Amanda",
			Age:  16,
		},
		{
			Name: "Steven",
			Age:  28,
		},
	}

    // Sort users by their age
	sort.Slice(users, func(i, j int) bool {
		return users[i].Age < users[j].Age
	})
	fmt.Println("Sorted users by age: ", users)

	// Stable sort
	sort.SliceStable(users, func(i, j int) bool {
		return users[i].Age < users[j].Age
	})
	fmt.Println("Sorted users by age: ", users)
}

透過實作 sort.Interface 來自訂排序

最後,讓我們看一下在 Go 中對原始類型的集合或使用者自訂的 struct 進行排序的最通用方式。要啟用對任何類型集合的自訂排序,你需要定義一個相對應的類型並實作 sort package 提供的通用 Interface。該 Interface 包含以下方法:

type Interface interface {
	// Len is the number of elements in the collection.
	Len() int

	// Less reports whether the element with index i must sort before the element with index j.
	// If both Less(i, j) and Less(j, i) are false, then the elements at index i and j are considered equal.
	Less(i, j int) bool

	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

實作上述 Interface 後,你可以使用 Sort()Stable() 函數對任何實作 sort.Interface 介面的集合進行排序。

讓我們透過一個範例來理解:

package main

import (
	"fmt"
	"sort"
)

type User struct {
	Name string
	Age  int
}

// Define a collection type that implements sort.Interface
type UsersByAge []User

func (u UsersByAge) Len() int {
	return len(u)
}
func (u UsersByAge) Swap(i, j int) {
	u[i], u[j] = u[j], u[i]
}
func (u UsersByAge) Less(i, j int) bool {
	return u[i].Age < u[j].Age
}

func main() {
	users := []User{
		{
			Name: "Rajeev",
			Age:  28,
		},
		{
			Name: "Monica",
			Age:  31,
		},
		{
			Name: "John",
			Age:  56,
		},
		{
			Name: "Amanda",
			Age:  16,
		},
		{
			Name: "Steven",
			Age:  28,
		},
	}

	// Sorting a slice of users by age (Sort may place equal elements in any order in the final result)
	sort.Sort(UsersByAge(users))
	fmt.Println("Sorted users by age: ", users)

	// Stable Sorting (Stavle sort preserves the original input order of equal elements)
	sort.Stable(UsersByAge(users))
	fmt.Println("[Stable] Sorted users by age: ", users)
}
$ go run custom-sorting-struct.go
Sorted users by age:  [{Amanda 16} {Rajeev 28} {Steven 28} {Monica 31} {John 56}]
[Stable] Sorted users by age:  [{Amanda 16} {Rajeev 28} {Steven 28} {Monica 31} {John 56}]

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK