go语言简单快速的按顺序遍历kv结构(map)

news2025/2/13 8:05:48

文章目录

  • 需求描述
    • 用map实现
    • 按照map的key排序
    • 用二维切片实现
    • 用结构体实现

需求描述

在go语言中,如果需要对map遍历,每次输出的顺序是不固定的,可以考虑存储为二维切片或结构体。
假设现在需要在页面的下拉菜单中展示一些基础的选项,需要服务端输出如下的结构:

{
    "code": 200000,
    "message": "请求成功",
    "data": [
        {
            "id": 1,
            "name": "中国"
        },
        {
            "id": 2,
            "name": "美国"
        },
        {
            "id": 3,
            "name": "韩国"
        },
        {
            "id": 4,
            "name": "新加坡"
        }
    ]
}

用map实现

首先,常规思维,考虑用map存储,实现方式如下:

先定义好常量值和映射关系,代码路径:gozero/internal/constants/commonConstants.go

package constants

const (
	// 国家常量值
	CountryChina     = 1
	CountryAmerica   = 2
	CountryKorea     = 3
	CountrySingapore = 4
)

var (
	//国家常量映射关系
	CountryMap = map[int]string{
		CountryChina:     "中国",
		CountryAmerica:   "美国",
		CountryKorea:     "韩国",
		CountrySingapore: "新加坡",
	}
)

然后在逻辑层使用上面定义的map:

代码路径:gozero/internal/logic/common/simpleselectlogic.go

func (l *SimpleSelectLogic) SimpleSelect(req *types.SimpleSelectRequest) (resp *utils.Response, err error) {
	paramType := req.Type
	var data interface{}
	switch paramType {
	case "country":
		data = mapToSlice(constants.CountryMap)
	case "others":
		data = nil
	}
	//成功返回
	return utils.SuccessResponse(data), nil
}

// 定义结构体
type Item struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

func mapToSlice(m map[int]string) []Item {
	// 提取所有的key
	keys := make([]int, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}

	// 将key和value组合成结构体切片
	sortedSlice := make([]Item, 0, len(m))
	for _, k := range keys {
		sortedSlice = append(sortedSlice, Item{ID: k, Name: m[k]})
	}

	return sortedSlice
}

通过上面的方式已经可以输出我们想要的结构了:

image-20250212181659720

但是,多运行几次就会发现,每次运行后的顺序并不一致,因为go中的map的遍历是不保证顺序的。

那么,直接在遍历的时候对key进行排序再按照key的顺序输出是否可行?尝试如下:

按照map的key排序

mapToSlice方法中加上对key的排序:

func mapToSortedSlice(m map[int]string) []Item {
	// 提取所有的key
	keys := make([]int, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}

	// 对key进行排序
	sort.Ints(keys)

	// 根据排序后的key顺序,将key和value组合成结构体切片
	sortedSlice := make([]Item, 0, len(m))
	for _, k := range keys {
		sortedSlice = append(sortedSlice, Item{ID: k, Name: m[k]})
	}

	return sortedSlice
}

这样修改后,可以保证输出的都是按照key由小到大排序的结果。

但是,假如现在有一种情况,产品要求在已有的下拉选项中插入一个新的选项值,并且顺序在中间。比如加入一个“英国”的选项,在“美国”后面,我们修改常量枚举值如下:

package constants

const (
	// 国家常量值
	CountryChina     = 1
	CountryAmerica   = 2
	CountryEngland   = 5 //增加的"英国"的枚举值
	CountryKorea     = 3
	CountrySingapore = 4
)

var (
	//国家常量映射关系
	CountryMap = map[int]string{
		CountryChina:     "中国",
		CountryAmerica:   "美国",
		CountryEngland:   "英国", //增加的"英国"排在"美国"下面
		CountryKorea:     "韩国",
		CountrySingapore: "新加坡",
	}
)

按照上面的方法,运行后会发现,新增加的枚举值排在了最后面:

image-20250212182455332

这是因为在mapToSortedSlice方法中根据map的key排序后,后来新增的key是5,所以会排在最后面。由于已有的key(1-4)不能修改,那么只能考虑再定义一个排序的切片来自定义需要排序的数据:

CountrySort = []int{
		CountryChina,
		CountryAmerica,
		CountryEngland,
		CountryKorea,
		CountrySingapore,
	}

然后在 mapToSortedSlice 方法中对上面的CountrySort进行排序后遍历。这种方法可以实现需求,但是会比较麻烦。因此,我决定改为使用二维切片来存储数据。

用二维切片实现

package constants

const (
	// 国家常量值--改为存储字符串
	CountryStrChina     = "1"
	CountryStrAmerica   = "2"
	CountryStrEngland   = "5"
	CountryStrKorea     = "3"
	CountryStrSingapore = "4"
)

var (
	//国家常量映射关系--切片存储
	CountrySlice = [][]string{
		{CountryStrChina, "中国"},
		{CountryStrAmerica, "美国"},
		{CountryStrEngland, "英国"},
		{CountryStrKorea, "韩国"},
		{CountryStrSingapore, "新加坡"},
	}
)

然后,处理切片的函数如下:

func formatSlice(m [][]string) []Item {
	// 根据排序后的key顺序,将key和value组合成结构体切片
	sortedSlice := make([]Item, 0, len(m))
	for _, v := range m {
		id, _ := strconv.Atoi(v[0])
		sortedSlice = append(sortedSlice, Item{ID: id, Name: v[1]})
	}
	return sortedSlice
}

调用一下:

func (l *SimpleSelectLogic) SimpleSelect(req *types.SimpleSelectRequest) (resp *utils.Response, err error) {
	paramType := req.Type
	var data interface{}
	switch paramType {
	case "country":
		//data = mapToSortedSlice(constants.CountryMap)
		data = formatSlice(constants.CountrySlice)
	case "others":
		data = nil
	}
	//成功返回
	return utils.SuccessResponse(data), nil
}

输出结果验证一下,会发现按照我们定义二维切片的顺序输出了:

image-20250212183415855

至此,问题解决。

如果你也需要在go中按顺序遍历kv结构,并且想偷个懒,那么不妨试试这样的方式。如果还想再偷懒,那么可以连常量都省去了,直接这么写:

//国家常量映射关系--切片存储-省去常量
CountrySliceSimple = [][]string{
  {"1", "中国"},
  {"2", "美国"},
  {"5", "英国"},
  {"3", "韩国"},
  {"4", "新加坡"},
}

用结构体实现

当然,也可以直接在定义的时候存储为结构体:

package constants

const (
	// 国家常量值
	CountryChina     = 1
	CountryAmerica   = 2
	CountryEngland   = 5 //增加的"英国"的枚举值
	CountryKorea     = 3
	CountrySingapore = 4

	//国家常量映射关系--结构体存储
	CountryStruct = []struct {
		Id   int    `json:"id"`
		Name string `json:"name"`
	}{
		{CountryChina, "中国"},
		{CountryAmerica, "美国"},
		{CountryEngland, "英国"},
		{999, "法国"},
		{CountryKorea, "韩国"},
		{CountrySingapore, "新加坡"},
	}
)

使用的时候也不需要转换了:

func (l *SimpleSelectLogic) SimpleSelect(req *types.SimpleSelectRequest) (resp *utils.Response, err error) {
	paramType := req.Type
	var data interface{}
	switch paramType {
	case "country":
		//data = mapToSortedSlice(constants.CountryMap) //使用map
		//data = formatSlice(constants.CountrySlice) //使用切片
		data = constants.CountryStruct //使用结构体
	case "others":
		data = nil
	}
	//成功返回
	return utils.SuccessResponse(data), nil
}

源代码:https://gitee.com/rxbook/go-demo-2025/tree/master/gozero

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【竞技宝】LOL-LPL:EDG3-0零封LNG

北京时间2月12日,英雄联盟LPL2025正在如火如荼的进行之中,昨日迎来LNG对阵EDG,以下是本场比赛的详细战报。 第一局: EDG:杰斯、赵信、维克托、女枪、芮尔 LNG:猴子、猪妹、飞机、韦鲁斯、布隆 首局比赛,EDG在蓝色方,LNG在红色方。阵容方面,EDG点出了杰斯、赵信、维克托、女枪…

在fedora41中安装钉钉dingtalk_7.6.25.4122001_amd64

在Fedora-Workstation-Live-x86_64-41-1.4中安装钉钉dingtalk_7.6.25.4122001_amd64.deb 到官网下载钉钉Linux客户端com.alibabainc.dingtalk_7.6.25.4122001_amd64.deb https://page.dingtalk.com/wow/z/dingtalk/simple/ddhomedownload#/ 一、直接使用dpkg命令安装deb包报错…

看期货用的指标,可以提示买卖点和K线转折变颜色的主图指标源码下载

A:MA(CLOSE,17)ABS(MA(CLOSE,17)-REF(MA(CLOSE,17),1)); B:MA(CLOSE,17)MA(CLOSE,17)-REF(MA(CLOSE,17),1); 分界线:IF(MA(CLOSE,17)<B,B,MA(CLOSE,17)),COLORFF00FF,LINETHICK2; 操作线:分界线-(EMA(C,3)-分界线),COLOR00FFFF,LINETHICK2; GUP:MA(C,5),COLORWHITE,LINE…

【PS 2022】Adobe Genuine Service Alert 弹出

电脑总是弹出Adobe Genuine Service Alert弹窗 1. 不关掉弹窗并打开任务管理器&#xff0c;找到Adobe Genuine Service Alert&#xff0c;并右键进入文件所在位置 2 在任务管理器中结束进程并将文件夹中的 .exe 文件都使用空文档替换掉 3. 打开PS不弹出弹窗&#xff0c;解决&a…

30天开发操作系统 第 20 天 -- API

前言 大家早上好&#xff0c;今天我们继续努力哦。 昨天我们已经实现了应用程序的运行, 今天我们来实现由应用程序对操作系统功能的调用(即API, 也叫系统调用)。 为什么这样的功能称为“系统调用”(system call)呢&#xff1f;因为它是由应用程序来调用(操作)系统中的功能来完…

蓝桥杯(B组)-每日一题(求最大公约数最小公倍数)

题目&#xff1a; 代码展现&#xff1a; #include<iostream> using namespace std; int main() {int m,n,x,y;cin>>m>>n;//输入两个整数int b;bm%n;//取余数xm;//赋值yn;while(b)//当余数不为0的时候{xy;//辗转相除求最小公约数yb;bx%y;}cout<<y<&…

arduino扩展:Arduino Mega 控制 32 个舵机(参考表情机器人)

参考&#xff1a;表情机器人中使用22个舵机的案例 引言 在电子制作与自动化控制领域&#xff0c;Arduino 凭借其易用性和强大的扩展性备受青睐。Arduino Mega 作为其中功能较为强大的一款开发板&#xff0c;具备丰富的引脚资源&#xff0c;能够实现复杂的控制任务。舵机作为常…

基于51单片机的门禁刷卡器proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1j0KAmH5pVGWZWRpT6p5hBg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

mapbox进阶,添加绘图扩展插件,裁剪线

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

19.4.6 读写数据库中的二进制数据

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 需要北风数据库的请留言自己的信箱。 北风数据库中&#xff0c;类别表的图片字段在【数据表视图】中显示为Bitmap Image&#xff1…

MapReduce到底是个啥?

在聊 MapReduce 之前不妨先看个例子&#xff1a;假设某短视频平台日活用户大约在7000万左右&#xff0c;若平均每一个用户产生3条行为日志&#xff1a;点赞、转发、收藏&#xff1b;这样就是两亿条行为日志&#xff0c;再假设每条日志大小为100个字节&#xff0c;那么一天就会产…

Winform自定义控件与案例 - 构建炫酷的自定义环形进度条控件

文章目录 1、控件效果2、案例实现1、代码实现2、代码解释3、使用示例 4、总结 1、控件效果 2、案例实现 1、代码实现 代码如下&#xff08;示例&#xff09;&#xff1a; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; …

【SpringBoot苍穹外卖】debugDay03.5

1、AOP面向切面编程 1. Target(ElementType.METHOD) 作用&#xff1a;指定自定义注解可以应用的目标范围。 参数&#xff1a;ElementType 是一个枚举类&#xff0c;定义了注解可以应用的目标类型。 ElementType.METHOD 表示该注解只能用于方法上。 其他常见的 ElementType 值…

flink实时集成利器 - apache seatunnel - 核心架构详解

SeaTunnel&#xff08;原名 Waterdrop&#xff09;是一个分布式、高性能、易扩展的数据集成平台&#xff0c;专注于大数据领域的数据同步、数据迁移和数据转换。它支持多种数据源和数据目标&#xff0c;并可以与 Apache Flink、Spark 等计算引擎集成。以下是 SeaTunnel 的核心架…

视频理解新篇章:Mamba模型的探索与应用

人工智能咨询培训老师叶梓 转载标明出处 想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具&#xff08;限时免费&#xff09;。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Facto…

分形几何表明数学一直存在有首、末的无穷序列

分形几何表明数学一直存在有首、末的无穷序列。一有穷长直线段S可变为锯齿状图形G而由无穷多无穷短直线段连接而成。G和S一样有左、右两个端点。

Python接口自动化测试—接口数据依赖

一般在做自动化测试时&#xff0c;经常会对一整套业务流程进行一组接口上的测试&#xff0c;这时候接口之间经常会有数据依赖&#xff0c;那又该如何继续呢&#xff1f; 那么有如下思路&#xff1a; 抽取之前接口的返回值存储到全局变量字典中。初始化接口请求时&#xff0c;…

C++ 实践扩展(Qt Creator 联动 Visual Studio 2022)

​ 这里我们将在 VS 上实现 QT 编程&#xff0c;实现如下&#xff1a; 一、Vs 2022 配置&#xff08;若已安装&#xff0c;可直接跳过&#xff09; 点击链接&#xff1a;​​​​​Visual Studio 2022 我们先去 Vs 官网下载&#xff0c;如下&#xff1a; 等待程序安装完成之…

Java中性能瓶颈的定位与调优方法

Java中性能瓶颈的定位与调优方法 Java作为一种高效、跨平台的编程语言&#xff0c;广泛应用于企业级应用、服务器端开发、分布式系统等领域。然而&#xff0c;在面对大量并发、高负载的生产环境时&#xff0c;Java应用的性能瓶颈问题往往会暴露出来。如何定位并优化这些性能瓶…

openbmc sdbusplus接口使用(持续更新...)

1.说明 本节介绍如何使用sdbusplus&#xff0c;用来对应不同的场景。 可以参考之前的文章: https://blog.csdn.net/wit_yuan/article/details/145192471 建议阅读本篇文章一定要仔细阅读sd-bus specification 2.说明 2.1 简单server服务注册 本节参考: https://gitee.com…