go 结构体多字段多因素排序
前言
有时候我们需要处理一份数据,需要多个字段作为条件,联合进行排序。
代码
package main
import (
"fmt"
"sort"
)
// 数据类型
type Change struct {
user string
language string
lines int
}
// sort接口方法之一(Less)
type lessFunc func(p1, p2 *Change) bool
// 数据集类型, 与排序(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type multiSorter struct {
changes []Change
less []lessFunc
}
type OrderedBy []lessFunc
func (ob OrderedBy) Sort(changes []Change) {
ms := &multiSorter{
changes: changes,
less: ob,
}
sort.Sort(ms)
}
// Len 为sort接口方法之一
func (ms *multiSorter) Len() int {
return len(ms.changes)
}
// Swap 为sort接口方法之一
func (ms *multiSorter) Swap(i, j int) {
ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
}
// Less 为sort接口方法之一
func (ms *multiSorter) Less(i, j int) bool {
// 为了后面编写简便, 这里将需要比较的两个元素赋值给两个单独的变量
p, q := &ms.changes[i], &ms.changes[j]
// Try all but the last comparison.
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q):
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p):
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}
var changes = []Change{
{"gri", "Go", 100},
{"ken", "C", 150},
{"glenda", "Go", 200},
{"rsc", "Go", 200},
{"r", "Go", 100},
{"ken", "Go", 200},
{"dmr", "C", 100},
{"r", "C", 150},
{"gri", "Smalltalk", 80},
}
func main() {
// 预定义排序函数: 按照姓名升序排列
user := func(c1, c2 *Change) bool {
return c1.user < c2.user
}
// 预定义排序函数: 按照语言升序排列
language := func(c1, c2 *Change) bool {
return c1.language < c2.language
}
// 预定义排序函数: 按照行数升序排列
increasingLines := func(c1, c2 *Change) bool {
return c1.lines < c2.lines
}
//预定义排序函数: 按照行数降序排列
decreasingLines := func(c1, c2 *Change) bool {
return c1.lines > c2.lines
}
// 按照姓名升序排列
OrderedBy([]lessFunc{user}).Sort(changes)
fmt.Println("By user:\t\t", changes)
// 按照姓名升序排列, 姓名相同的按行数升序排列
OrderedBy([]lessFunc{user, increasingLines}).Sort(changes)
fmt.Println("By user,<lines:\t\t", changes)
// 按姓名升序排列, 姓名相同的按行数降序排列
OrderedBy([]lessFunc{user, decreasingLines}).Sort(changes)
fmt.Println("By user,>lines:\t\t", changes)
// 按语言升序排列, 语言相同按行数升序排列
OrderedBy([]lessFunc{language, increasingLines}).Sort(changes)
fmt.Println("By language,<lines:\t", changes)
// 按语言升序排列, 语言相同按行数升序排列, 行数也相同的, 按姓名升序排列
OrderedBy([]lessFunc{language, increasingLines, user}).Sort(changes)
fmt.Println("By language,<lines,user:", changes)
}
运行结果
By user: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {r Go 100} {gri Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
go 结构体多字段多因素排序的更多相关文章
- ABAP中不修改内表参照的结构,给内表/结构体增加字段
Situation: DATA: itab TYPE STANDARD TABLE OF zsrsodtla_stru1, wa_itab TYPE zsrsodtla_str ...
- go语言之进阶篇非结构体匿名字段
1.非结构体匿名字段 示例 : package main import "fmt" type mystr string //自定义类型,给一个类型改名 type Person st ...
- Golang通过反射拼接一个结构体所有字段
golang通过反射拼接一个结构体所有字段 需求 将一个结构体所有字段以"|"连接拼接成字符串 golang 不同类型拼接成string使用Sprintf比较麻烦,如果一个结构体有 ...
- Java的 「 “ 结构体 ”」 与 「 “ 自定义排序 ” 」
Java里面的结构体可以靠class来实现,如果相对结构体进行排序,需要写一个接口,class 自定义的名字 implements Comparator<结构体(自己定义的class类的名字)& ...
- C++线性表通过结构体实现操作和结构体字符串快速排序和shell排序结合
#include<iostream> #include<string> #define ml 10 using namespace std; typedef struct{// ...
- 为什么建议使用Guid结构体做为数据库及排序时的主键
在.net2.0中,Guid结构体表示一个全局唯一标识符,是一个在生成时就可以肯定为全世界唯一的16字节值.Guid在数据库中通常可以作为各种排序的主键.比如 public class Company ...
- [GO]非结构体匿名字段
package main import ( "fmt" ) type mystr string //给一个类型重命名 type Person struct { name strin ...
- matlab学习笔记12_2创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段
一起来学matlab-matlab学习笔记12 12_2 结构体 创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段 觉得有用的话 ...
- 利用sort对结构体进行排序
我定义了一个学生类型的结构体来演示sort排序对结构体排序的用法 具体用法看代码 #include<iostream> #include<string> #include< ...
- C++ list结构体变量排序
以下内容是自己整理的根据结构体里面的不同变量,对list排序的实例,若有问题可以留言.仅供参考. #include <iostream> #include <list> #in ...
随机推荐
- Qt/C++音视频开发70-无感切换通道/无缝切换播放视频/多通道流畅切换/不同视频打开无缝切换
一.前言 之前就写过这个方案,当时做的是ffmpeg内核版本,由于ffmpeg内核解析都是代码实现,所以无缝切换非常完美,看不到丝毫的中间切换过程,看起来就像是在一个通道画面中.其实这种切换只能说是取 ...
- Qt项目架构经验总结
(一)通用规则 除了极小的微型demo级别项目外,其余项目建议用pri分门别类不同文件夹存放代码文件,方便统一管理和查找. 同类型功能的类建议统一放在一起,如果该目录下代码文件数量过多,也建议拆分多个 ...
- [转]Windows系统下彻底删除Windows.old 文件夹的方法
系统是直接硬盘安装的,导致c盘产生了旧系统的文件夹Windows.old,占用很大的磁盘空间,删也删不掉,咋办?不要紧,下面大神来教你神操作!!! 1.打开"计算机",选择C盘,进 ...
- eclipse中汉字横着的问题解决
最近在eclipse中加上中午注释,出现那种汉字是横着的情况,解决方案如下: 方法一: 同一种字体有两种显示方式,比如Fixedsys Excelsior 3.01和@Fixedsys Excelsi ...
- Windows应用开发-常用工具集推荐
.NET/WPF开发 Visual Studio 最新版本是VS2022,官网下载:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具 VsColorOutput 控制台 ...
- FreeSWITCH日志功能分析及apr模拟
操作系统版本:Debian 12.5_x64 FreeSWITCH版本: 1.10.11 apr库版本:apr-1.7.4 & apr-util-1.6.3 gcc版本: 12.2.0 日 ...
- C Primer Plus 第6版 第二章 编程练习参考答案
编译环境VS Code+WSL GCC /*第一题*************************/ #include<stdio.h> int main() { printf(&quo ...
- 【开源】C#上位机必备高效数据转换助手
一.前言 大家好!我是付工. 我们在进行上位机开发时,从设备端获取到的数据之后,需要进行一定的数据处理及转换,才能生成我们需要用的数据. 这其中就涉及到了各种数据类型之间的相关转换,很多非科班出身的电 ...
- Java工具类HttpClientUtil
1. 依赖包 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId> ...
- 巧用VTable打造炫酷金字塔图表
在数据分析和可视化领域,表格是展示数据直观.有效的方式之一.今天,就让我们来探索如何利用VTable这个强大的表格组件,制作出既美观又富有信息量的金字塔图表,以及深入了解VTable中各种单元格类型的 ...