Golang 结构体数组、按结构体中的某些字段进行排序

2,885 阅读2分钟

Go语言中的sort包帮我们实现了对任一类型的数组进行排序。

对于将要排序的数组类型只需要我们实现下面三种方法:

type Interface interface {
	Len() int  // 数组长度
	Less(i, j int) bool //两个元素的大小比较
	Swap(i, j int) // 交换两个元素
}

下面我们简单看下sort.Sort 源码,着急忙慌被老板催着赶进度的,可以直接看注释部分了解~

//go/src/sort/sort.go
func Sort(data Interface) {
	n := data.Len()
	quickSort(data, 0, n, maxDepth(n))
}
//data是一个数组类型的对象,可以看到这里会调用data的Len()方法,排序是通过快排的方式实现。

func quickSort(data Interface, a, b, maxDepth int) {
	for b-a > 12 {
		if maxDepth == 0 {
			heapSort(data, a, b)
			return
		}
		maxDepth--
		mlo, mhi := doPivot(data, a, b)
		if mlo-a < b-mhi {
			quickSort(data, a, mlo, maxDepth)
			a = mhi 
		} else {
			quickSort(data, mhi, b, maxDepth)
			b = mlo 
		}
	}
	if b-a > 1 {
		for i := a + 6; i < b; i++ {
			if data.Less(i, i-6) {
				data.Swap(i, i-6)
			}
		}
		insertionSort(data, a, b)
	}
}
//这是快排的实现逻辑,可以看到这里会调用data的两种方法:
// data.Less()   data.Swap(i,j ints)

举个栗子

有一个Student数组,现要对其按照年龄大小,从小到大进行排序

type Student struct {
	Name     string
	Age      int
}

students:=[]Student{
		{Name: "tom",Age: 10},
		{Name: "smith",Age: 12},
		{Name: "danny",Age: 13},
		{Name: "jack",Age: 12},
		{Name: "boom",Age: 12},
}

第一步,构造数组对象

type StudentArray []Student

第二步,实现 Len(),Less(),Swap() 三种方法

func (array StudentArray) Len() int  {
	return len(array)
}

func (array StudentArray) Less(i,j int) bool {
	return array[i].Age < array[j].Age   //从小到大, 若为大于号,则从大到小
}

func (array StudentArray) Swap(i,j int) {
	array[i],array[j] = array[j],array[i]
}

第三步,调用sort包

sort.Sort(StudentArray(students))

第四步,输出排序后的结果

fmt.Println(students)
// [{tom 10} {smith 12} {jack 12} {boom 12} {danny 13}]

现在呢,又提出了一个新的排序需求:

  • 从小到大按年龄排序
  • 当年龄相同时,按照名字排序

问题不大,我们只需要更新Less()方法即可:

func (array StudentArray) Less(i,j int) bool {
	if  array[i].Age == array[j].Age {
		return array[i].Name < array[j].Name
	}
	return array[i].Age < array[j].Age
}

此时再进行排序

sort.Sort(StudentArray(students))
fmt.Println(students)
//[{tom 10} {boom 12} {jack 12} {smith 12} {danny 13}]