golang 使用 sort.Interface 实现正反排序

排序是编程中经常要遇到的一个算法,通常这个算法底层的实现都无需使用者考虑,go 语言也是如此,它提供了一个简单的实现模式让排序即插即用,能对任一序列排序。官方已经实现了3个常用的 slice 的排序,[]int,[]float64,[]string,这三个函数如下,可以直接使用。
package sort

func Ints(a []int) { Sort(IntSlice(a)) }

func Float64s(a []float64) { Sort(Float64Slice(a)) }

func Strings(a []string) { Sort(StringSlice(a)) }
 
除此之外的序列该如何实现呢,go 语言提供了 sort.Interface,只要实现此接口方法的序列类型,都可以排序
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)
}
 
来看一个结构体 slice 的排序,我们必须先了解 slice 有自己的底层数组,最终是对这个底层数组的顺序的修改,这也就是原地排序,所以我们定义的 groups 在每次排序都是对它/或者说它的底层数组排序。

同时还需理解 sort.Reverse 返回的并不是一个已经排序的序列,开看看源码

// 从一个 Interface 返回另一个 Interface
func Reverse(data Interface) Interface { return &reverse{data} }

// 通过一个结构体来反转排序
type reverse struct { Interface }
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }

// 相当于定义了一个与下面相反的代码,一个是大于号,一个是小于号
func (s OneGroups) Less(i, j int) bool { return s[i].Size > s[j].Size }

所以我们能理解 sort.Reverse 仅仅是偷换了一个 Less,然后再执行一次 sort.Sort 函数,就实现了 groups 的反转了
 
package main

import (
   "fmt"
   "sort"
)

func main() {
   groups := OneGroups{
      {"d8f4f", "Golang", 30},
      {"d9f4a", "Python", 20},
      {"u8f3n", "Java", 10},
      {"t7y68", "Ruby", 25}}

   // 正序
   sort.Sort(groups)
   for _, g := range groups {
      fmt.Printf("%v\t", g)
   }

   fmt.Println("")
   // 反转
   sort.Sort(sort.Reverse(groups))
   for _, g := range groups {
      fmt.Printf("%v\t", g)
   }
}

type OneGroup struct {
   CatId string
   Name  string
   Size  int
}

type OneGroups []*OneGroup

func (s OneGroups) Len() int           { return len(s) }
func (s OneGroups) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s OneGroups) Less(i, j int) bool { return s[i].Size < s[j].Size }
输出结果
F:\github.com\iissy\goexample\sort>go run main.go
&{u8f3n Java 10}        &{d9f4a Python 20}      &{t7y68 Ruby 25}        &{d8f4f Golang 30}
&{d8f4f Golang 30}      &{t7y68 Ruby 25}        &{d9f4a Python 20}      &{u8f3n Java 10} 
Posted by 何敏 on 2020-02-29 11:23:25