当前位置: 首页 > news >正文

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

文章目录

  • 需求描述
    • 用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

相关文章:

  • 网络工程师 (32)TRUNK
  • c++20新特性
  • B+Tree在mysql中的使用
  • 17.推荐系统的在线学习与实时更新
  • FANUC机器人示教器中如何显示或关闭寄存器或IO的注释信息?
  • 缓存穿透问题及解决方案
  • 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-23- 操作鼠标拖拽 - 番外篇(详细教程)
  • Windows安装 WSL2、Ubuntu 、docker(详细步骤 , 弃用 docker desktop )
  • Redis 数据类型 Hash 哈希
  • 海康威视人脸门禁对接开发准备篇
  • 【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.3 RNN与LSTM在自然语言处理中的应用案例】
  • docker快速部署oracle11g
  • Unity3D 移动端 CPU 性能调优详解
  • Oracle常用导元数据方法
  • cap4:YoloV5的TensorRT部署指南(python版)
  • Unity 卡死排查方法(游戏死循环、打包卡死)
  • 批量查询linux下可执行程序缺少的依赖
  • ollama离线环境部署deepseek及对话网站开发
  • 思科、华为、H3C常用命令对照表
  • 探索RDMA技术:从基础到实践
  • 我国外汇储备规模连续17个月稳定在3.2万亿美元以上
  • 中俄领导人将讨论从俄罗斯经蒙古至中国天然气管道项目?外交部回应
  • 魔都眼|上海多家商场打开绿色通道,助力外贸出口商品转内销
  • 巴基斯坦所有主要城市宣布进入紧急状态,学校和教育机构停课
  • 中标多家学校采购项目的App查成绩需付费?涉事公司回应
  • 消费者在天猫一旗舰店换手机电池疑遭套路致手机损坏,平台已介入