Golang如何用sort包实现自定义排序

来源:菜鸟站长作者:葵司头衔:网络博主
导读:本期聚焦于小伙伴创作的《Golang如何用sort包实现自定义排序》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Golang如何用sort包实现自定义排序》有用,将其分享出去将是对创作者最好的鼓励。

在Golang的标准库中,sort包提供了完整的排序功能,不仅可以处理int、string等内置类型的默认排序,还支持开发者通过实现特定接口来自定义排序规则,满足切片、结构体集合等不同场景的排序需求。sort包的核心设计基于接口抽象,只要类型实现了sort.Interface接口定义的三个方法,就可以使用sort包提供的排序函数完成排序操作。

Golang如何用sort包实现自定义排序

sort包的核心接口

sort.Interface接口是自定义排序的基础,该接口定义了三个必须实现的方法,具体如下:

  • Len() int:返回集合的长度,也就是需要排序的元素总数
  • Less(i, j int) bool:判断索引i的元素是否应该排在索引j的元素前面,返回true表示i位置的元素更小,排在前面
  • Swap(i, j int):交换索引i和索引j位置的两个元素

只要自定义类型实现了这三个方法,就可以调用sort.Sort()函数完成排序,同时sort包也提供了sort.Stable()函数用于稳定排序,稳定排序会保持相等元素的原有相对顺序。

切片自定义排序实现

对于内置类型的切片,sort包已经提供了默认的排序函数,比如sort.Ints()用于int切片升序排序,sort.Strings()用于字符串切片升序排序。如果需要自定义切片的排序规则,比如int切片降序排序,就需要自定义类型实现sort.Interface接口。

int切片降序排序示例

下面的代码实现了int切片的降序排序:

package main

import (
	"fmt"
	"sort"
)

// 定义自定义类型,基于[]int
type IntSliceDesc []int

// 实现Len方法,返回切片长度
func (s IntSliceDesc) Len() int {
	return len(s)
}

// 实现Less方法,i位置元素大于j位置元素时返回true,实现降序
func (s IntSliceDesc) Less(i, j int) bool {
	return s[i] > s[j]
}

// 实现Swap方法,交换两个位置的元素
func (s IntSliceDesc) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func main() {
	nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
	// 将[]int转换为自定义类型
	sortNums := IntSliceDesc(nums)
	// 调用sort.Sort进行排序
	sort.Sort(sortNums)
	fmt.Println("降序排序后的切片:", sortNums)
}

运行上述代码,输出结果为:降序排序后的切片: [9 6 5 4 3 2 1 1],可以看到切片已经按照从大到小的顺序完成排序。

字符串切片按长度排序示例

如果需要对字符串切片按照字符串长度进行排序,同样可以通过实现接口完成:

package main

import (
	"fmt"
	"sort"
)

// 定义自定义类型,基于[]string
type StringSliceByLength []string

func (s StringSliceByLength) Len() int {
	return len(s)
}

// 按字符串长度升序排序,长度相同则按字典序排序
func (s StringSliceByLength) Less(i, j int) bool {
	if len(s[i]) != len(s[j]) {
		return len(s[i]) < len(s[j])
	}
	return s[i] < s[j]
}

func (s StringSliceByLength) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func main() {
	strs := []string{"go", "golang", "python", "java", "c", "javascript"}
	sortStrs := StringSliceByLength(strs)
	sort.Sort(sortStrs)
	fmt.Println("按长度排序后的字符串切片:", sortStrs)
}

运行结果为:按长度排序后的字符串切片: [c go java python golang javascript],符合按长度升序的排序预期。

结构体自定义排序实现

在实际开发中,经常需要对结构体切片进行排序,比如按照结构体的某个字段排序,或者按照多个字段的优先级排序,这时候同样需要实现sort.Interface接口,在Less方法中定义排序规则即可。

单字段排序示例

假设我们有一个学生结构体,包含姓名和分数两个字段,需要按照分数从高到低排序:

package main

import (
	"fmt"
	"sort"
)

// 定义学生结构体
type Student struct {
	Name   string
	Score  int
}

// 定义学生切片类型
type StudentSlice []Student

func (s StudentSlice) Len() int {
	return len(s)
}

// 按分数降序排序,分数相同则按姓名字典序升序
func (s StudentSlice) Less(i, j int) bool {
	if s[i].Score != s[j].Score {
		return s[i].Score > s[j].Score
	}
	return s[i].Name < s[j].Name
}

func (s StudentSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func main() {
	students := []Student{
		{Name: "张三", Score: 85},
		{Name: "李四", Score: 92},
		{Name: "王五", Score: 85},
		{Name: "赵六", Score: 78},
	}
	sortStudents := StudentSlice(students)
	sort.Sort(sortStudents)
	fmt.Println("按分数排序后的学生列表:")
	for _, stu := range sortStudents {
		fmt.Printf("姓名:%s,分数:%dn", stu.Name, stu.Score)
	}
}

运行结果为:

按分数排序后的学生列表:
姓名:李四,分数:92
姓名:张三,分数:85
姓名:王五,分数:85
姓名:赵六,分数:78

可以看到分数高的学生排在前面,分数相同的张三和王五按照姓名字典序排列,符合我们的排序规则。

多字段优先级排序示例

如果需要按照多个字段的优先级排序,比如先按年龄升序,年龄相同再按工资降序,只需要在Less方法中先判断第一个字段,第一个字段相等时再判断第二个字段即可:

package main

import (
	"fmt"
	"sort"
)

// 定义员工结构体
type Employee struct {
	Name   string
	Age    int
	Salary int
}

// 定义员工切片类型
type EmployeeSlice []Employee

func (e EmployeeSlice) Len() int {
	return len(e)
}

// 先按年龄升序,年龄相同按工资降序
func (e EmployeeSlice) Less(i, j int) bool {
	if e[i].Age != e[j].Age {
		return e[i].Age < e[j].Age
	}
	return e[i].Salary > e[j].Salary
}

func (e EmployeeSlice) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}

func main() {
	employees := []Employee{
		{Name: "员工A", Age: 25, Salary: 8000},
		{Name: "员工B", Age: 30, Salary: 12000},
		{Name: "员工C", Age: 25, Salary: 10000},
		{Name: "员工D", Age: 30, Salary: 10000},
	}
	sortEmployees := EmployeeSlice(employees)
	sort.Sort(sortEmployees)
	fmt.Println("按年龄和工资排序后的员工列表:")
	for _, emp := range sortEmployees {
		fmt.Printf("姓名:%s,年龄:%d,工资:%dn", emp.Name, emp.Age, emp.Salary)
	}
}

运行结果为:

按年龄和工资排序后的员工列表:
姓名:员工C,年龄:25,工资:10000
姓名:员工A,年龄:25,工资:8000
姓名:员工B,年龄:30,工资:12000
姓名:员工D,年龄:30,工资:10000

可以看到年龄25的员工排在前面,同年龄的员工C工资更高排在前面,年龄30的员工同理,符合多字段排序的预期。

简化自定义排序的方法

如果觉得每次实现三个方法比较繁琐,sort包还提供了sort.Slice()函数,该函数只需要传入一个比较函数就可以完成排序,不需要自定义类型实现接口,使用起来更加简洁。比如上面的学生排序用sort.Slice()实现如下:

package main

import (
	"fmt"
	"sort"
)

type Student struct {
	Name  string
	Score int
}

func main() {
	students := []Student{
		{Name: "张三", Score: 85},
		{Name: "李四", Score: 92},
		{Name: "王五", Score: 85},
		{Name: "赵六", Score: 78},
	}
	// 使用sort.Slice,传入比较函数,i位置元素应该排在j前面时返回true
	sort.Slice(students, func(i, j int) bool {
		if students[i].Score != students[j].Score {
			return students[i].Score > students[j].Score
		}
		return students[i].Name < students[j].Name
	})
	fmt.Println("按分数排序后的学生列表:")
	for _, stu := range students {
		fmt.Printf("姓名:%s,分数:%dn", stu.Name, stu.Score)
	}
}

该方式和之前实现接口的效果完全一致,但是代码更加简洁,适合临时需要自定义排序的场景。如果需要复用排序逻辑,还是建议实现sort.Interface接口,方便多处调用。

Golangsort包自定义排序切片排序结构体排序修改时间:2026-07-14 15:03:45

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。