Golang-Map有序输出——使用orderedmap库实现
前言
工作中遇到一个问题:需要导出一个MySQL表格,表格内容由sql查询得来。但现在发现,所导出的表格中,各列的顺序不确定。多次导出, 每一次的序列顺序也是不定的。
因此确定是后端,Map使用相关导致的问题。自己想法是——创一个map[int]map{}类型,即map套map。里面的map保存原有内容,int保存序号。
经网络搜索,发现已经有开源库提供了此功能,即https://github.com/iancoleman/orderedmap库。因此对他进行学习。
功能概述
Golang内置的Map是无需的,而OrderedMap则是提供了一个有顺序的Map。其顺序是插入时的顺序。
下面是官方文档中提供的功能描述:
package mainimport ("encoding/json""github.com/iancoleman/orderedmap""sort"
)func main() {// use New() instead of o := map[string]interface{}{}o := orderedmap.New()// use SetEscapeHTML() to whether escape problematic HTML characters or not, defaults is trueo.SetEscapeHTML(false)// use Set instead of o["a"] = 1o.Set("a", 1)// add some value with special characterso.Set("b", "\\.<>[]{}_-")// use Get instead of i, ok := o["a"]val, ok := o.Get("a")// use Keys instead of for k, v := range okeys := o.Keys()for _, k := range keys {v, _ := o.Get(k)}// use o.Delete instead of delete(o, key)o.Delete("a")// serialize to a json string using encoding/jsonbytes, err := json.Marshal(o)prettyBytes, err := json.MarshalIndent(o, "", " ")// deserialize a json string using encoding/json// all maps (including nested maps) will be parsed as orderedmapss := `{"a": 1}`err := json.Unmarshal([]byte(s), &o)// sort the keyso.SortKeys(sort.Strings)// sort by Pairo.Sort(func(a *orderedmap.Pair, b *orderedmap.Pair) bool {return a.Value().(float64) < b.Value().(float64)})
}
其主要用法如下:
通过orderedmap.New()新建一个Map。
通过o.Set("a", 1)设置Map中的元素内容。 (注意:key必须是string)
通过o.Get("a")获取map内容。
通过keys达到for range效果。
通过o.Delete("a")进行元素删除。
通过SortKeys和Sort进行排序。
源码阅读
OrderedMap的源码,包含注释等在内,一共266行,可谓是十分简短。

其中,一共有如下的方法可使用:

OrderedMap的数据结构
New()出来的那个Map是这样:
type OrderedMap struct {keys []stringvalues map[string]interface{}escapeHTML bool
}
其中:escapeHTML是用来表示是否转义HTML字符,默认为true表示转义。可以调用SetEscapeHTML(false)方法来设置不转义HTML字符。
剩余keys是[]string,values是map。
OrderedMap有序输出的原理
做这样一个测试:
func main() {o := orderedmap.New()o.Set("key2", "v2")o.Set("key3", "v3")o.Set("key1", 1)fmt.Println(o.Keys())fmt.Println(o.Values())}
其中,keys和values分别用于返回所有的key和value。
func (o *OrderedMap) Keys() []string {return o.keys
}func (o *OrderedMap) Values() map[string]interface{} {return o.values
}
输出结果为:

我们可以看到,其key是按输入顺序进行排列的切片,value是保存了对应key和value的map。
在输出时,通过定序的key,去访问不定序的value,最终输出时实现定序的效果。(定序:指与输入顺序相同)。
基础方法
初始化
通过New方法生成一个OrderedMap,其中可以通过SetEscapeHTML对该参数进行设置。
func New() *OrderedMap {o := OrderedMap{}o.keys = []string{}o.values = map[string]interface{}{}o.escapeHTML = truereturn &o
}func (o *OrderedMap) SetEscapeHTML(on bool) {o.escapeHTML = on
}
值的设置、查看及删除
通过Get获取指定key值对应的value。
通过Set对键值对进行设置。
通过Delete删除键值对。
func (o *OrderedMap) Get(key string) (interface{}, bool) {val, exists := o.values[key]return val, exists
}func (o *OrderedMap) Set(key string, value interface{}) {_, exists := o.values[key]if !exists {o.keys = append(o.keys, key)}o.values[key] = value
}func (o *OrderedMap) Delete(key string) {// check key is in use_, ok := o.values[key]if !ok {return}// remove from keysfor i, k := range o.keys {if k == key {o.keys = append(o.keys[:i], o.keys[i+1:]...)break}}// remove from valuesdelete(o.values, key)
}
获取所有kv值
通过Keys()获取所有的key。
通过Values()获取所有的Value。
func (o *OrderedMap) Keys() []string {return o.keys
}func (o *OrderedMap) Values() map[string]interface{} {return o.values
}
Sort和SortKeys方法
SortKeys()方法
// SortKeys Sort the map keys using your sort func
func (o *OrderedMap) SortKeys(sortFunc func(keys []string)) {sortFunc(o.keys)
}
即根据传入的方法规则,对key值进行排序。例如,按字母顺序排:
o.SortKeys(sort.Strings)
测试:
func main() {o := orderedmap.New()o.Set("key2", "v2")o.Set("key3", "v3")o.Set("key1", 1)fmt.Println(o.Keys())fmt.Println(o.Values())o.SortKeys(sort.Strings)fmt.Println(o.Keys())fmt.Println(o.Values())
}
结果:

Sort()方法
源码如下:
// Sort Sort the map using your sort func
func (o *OrderedMap) Sort(lessFunc func(a *Pair, b *Pair) bool) {pairs := make([]*Pair, len(o.keys))for i, key := range o.keys {pairs[i] = &Pair{key, o.values[key]}}sort.Sort(ByPair{pairs, lessFunc})for i, pair := range pairs {o.keys[i] = pair.key}
}
其中,pair如下:
type Pair struct {key stringvalue interface{}
}
该方法内,首先通过pair保留每一个键值对。之后哦通过传入的lessFunc进行排序,再按照排序后的顺序,赋值到内部,从而实现排序。
用法示例:
// sort by Pair
o.Sort(func(a *orderedmap.Pair, b *orderedmap.Pair) bool {return a.Value().(float64) < b.Value().(float64)
})
Json相关
UnmarshalJSON方法,用于将JSON转换为有序MAP。
func (o *OrderedMap) UnmarshalJSON(b []byte) error {if o.values == nil {o.values = map[string]interface{}{}}err := json.Unmarshal(b, &o.values)if err != nil {return err}dec := json.NewDecoder(bytes.NewReader(b))if _, err = dec.Token(); err != nil { // skip '{'return err}o.keys = make([]string, 0, len(o.values))return decodeOrderedMap(dec, o)
}
MarshalJSON反之,序列化为JSON。
func (o OrderedMap) MarshalJSON() ([]byte, error) {var buf bytes.Bufferbuf.WriteByte('{')encoder := json.NewEncoder(&buf)encoder.SetEscapeHTML(o.escapeHTML)for i, k := range o.keys {if i > 0 {buf.WriteByte(',')}// add keyif err := encoder.Encode(k); err != nil {return nil, err}buf.WriteByte(':')// add valueif err := encoder.Encode(o.values[k]); err != nil {return nil, err}}buf.WriteByte('}')return buf.Bytes(), nil
}
最后还有decodeOrderedMap和decodeSlice两个方法,是辅助json转换时候所用的,在此不再阐述。
总结&心得
1、通过OrderedMap可以实现MAP的有序化,按输入顺序输出map的内容,或按自定义规则排序后进行输出。
2、使用OrderedMap会导致性能下降,不要过度依赖。
相关文章:
Golang-Map有序输出——使用orderedmap库实现
前言 工作中遇到一个问题:需要导出一个MySQL表格,表格内容由sql查询得来。但现在发现,所导出的表格中,各列的顺序不确定。多次导出, 每一次的序列顺序也是不定的。 因此确定是后端,Map使用相关导致的问题。…...
基础数学问题整理
最近刷了一些关于基础数学问题的题目,大致是关于组合数、分解质因数还有一些思维题,题目来自洛谷的【数学1】基础数学问题 - 题单 - 洛谷,很多思路还是之前没有见过的,都是简单到一般难度的题目(橙、题、绿题ÿ…...
【Linux】环境基础开发工具的使用(一)
前言:在此之前我们学习了一些Linux的权限,今天我们进一步学习Linux下开发工具的使用。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:Linux的深度刨析 👈 💯代码仓库:卫卫周大胖的学习日记…...
突破编程_C++_面试(基础知识(5))
面试题9:什么是内存地址 内存地址是指计算机内存中存储变量或对象的地址。内存空间大小就是寻址能力,即能访问到多少个地址,比如 32 位机器内存空间大小就是 2^32 4294967296,也就是 4 GB 。每个变量或对象在内存中都有一个唯一…...
十分钟掌握Go语言==运算符与reflect.DeepEqual函数处理interface{}值的比较规则
在 Go 语言中,interface{} 类型是一种特殊的接口类型,它表示任意类型的值。你可以使用 运算符来检测任意两个 interface{} 类型值的相等性,比较的规则和一般的接口类型一样,需要满足以下条件: 两个 interface{} 值的…...
Unity3d Shader篇(一)— 顶点漫反射着色器解析
文章目录 前言一、顶点漫反射着色器是什么?1. 顶点漫反射着色器的工作原理 二、编写顶点漫反射着色器1. 定义属性2. 创建 SubShader3. 编写着色器程序段4. 完成顶点着色器5. 完成片段着色器 三、效果四、总结 前言 在 Unity 中,Shader 可以用来实现各种…...
WordPress主题YIA的文章页评论内容为什么没有显示出来?
有些WordPress站长使用YIA主题后,在YIA主题设置的“基本”中没有开启“一键关闭评论功能”,而且文章也是允许评论的,但是评论框却不显示,最关键的是文章原本就有的评论内容也不显示,这是为什么呢? 根据YIA主…...
选择低代码应该注意什么?如何选择?
我查看了几乎所有的介绍低代码的总结和分析报告,几乎都没有把低代码最底层的产品逻辑说清楚。今天我尝试不用复杂的技术名词,也不用代码,把这个事儿给大家说明白,低代码到底怎么回事儿!(人云亦云那些&#…...
橘子学linux调优之工具包的安装
今天在公司无聊的弄服务器,想着有些常用的工具包安装一下,这里就简单记录一下。 一、sysstat的安装和使用 1、安装 我是通过源码的方式安装的,这样的好处在于可以自由选择你的版本,很直观。 直接去github上找到sysstat的地址&a…...
函数的连续与间断【高数笔记】
【连续】 分类,分几个?每类特点? 连续条件,是同时满足还是只需其一? 【间断】 分类,分几个大类,又分几个小类?每类特点? 间断条件,是同时满足还是只需其一&am…...
游戏如何选择服务器
选择游戏服务器是一个综合性的过程,涉及到的因素包括但不限于游戏类型和规模、硬件配置、网络质量、安全性、服务商的声誉以及地理分布等。以下是一些具体的指导原则: 游戏类型和规模:根据游戏的具体需求来选择合适的服务器。例如࿰…...
ubuntu20安装mysql8
1.安装 sudo apt update sudo apt install mysql-server-8.0 -y2.查看运行状态 yantaoubuntu20:~$ sudo systemctl status mysql ● mysql.service - MySQL Community ServerLoaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:>Active: active …...
07 SB3之@HttpExchange(TBD)
HttpExchange是SpringBoot3的新特性. Spring Boot3 提供了新的 HTTP 的访问能力,封装了Http底层细节. 通过接口简化 HTTP远程访问,类似 Feign 功能。 SpringBoot 中定义接口提供 HTTP 服务 --> 框架生成的代理对象实现此接口 --> 框架生成的代理…...
Redis数据淘汰策略
Redis作为一种高性能的键值存储数据库,通常用于缓存和提高数据检索速度。然而,由于内存资源有限,当内存不足以容纳所有数据时,Redis就需要采取一些策略来删除部分数据,以确保新的数据能够被写入。这就引入了数据淘汰策…...
Git的一些基本操作
初始git 我们给出下面的一个场景,在大学里,一些老师在我们做完实验之后喜欢让我们交实验报告,假设我们有一个比较追求完美的老师和一个勤奋的学生,这个学生叫做小帅,那天小帅桑勤奋的完成实验报告,在第二天…...
Spring Boot中异步线程池@Async
很多业务场景需要使用异步去完成,比如:发送短信通知。要完成异步操作一般有两种: 1、消息队列MQ 2、线程池处理。 我们来看看Spring框架中如何去使用线程池来完成异步操作,以及分析背后的原理。 一. Spring异步线程池的接口类 …...
ArcGIS学习(五)坐标系-2
3.不同基准面坐标系之间的转换 在上一关中,我们学习了ArcGIS中的投影(投影栅格)工具,并以"WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”为例进行讲解。 "WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”代表的是同一个基准面下的两个坐标的转换。 …...
2024Node.js零基础教程(小白友好型),nodejs新手到高手,(五)NodeJS入门——http模块
044_http模块_创建HTTP服务端 hello,大家好,那这个小节我们来使用 nodejs 创建一个 http 的服务,有了这个 http 服务之后,我们就可以处理浏览器所发送过来的请求,并且还可以给这个浏览器返回响应。 顺便说一下&#x…...
sklearn.preprocessing 标准化、归一化、正则化
文章目录 数据标准化的原因作用归一化最大最小归一化针对规模化有异常的数据标准化线性比例标准化法log函数标准化法正则化Normalization标准化的意义数据标准化的原因 某些算法要求样本具有零均值和单位方差;需要消除样本不同属性具有不同量级时的影响: ① 数量级的差异将导…...
Windows系统编程(一) 文件与目录操作
以下程序需要包含<Windows.h>头文件 创建打开文件 HANDLE hFile CreateFile("D:\\rkvir.ini", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 此处打开文件,参数依次 已有文件的路径,注意…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
