Go语言map的多键索引——多个数值条件可以同时查询_xyz的博客-CSDN博客_go语言map的多键索引


本站和网页 https://blog.csdn.net/xyz/article/details/120072162 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

Go语言map的多键索引——多个数值条件可以同时查询_xyz的博客-CSDN博客_go语言map的多键索引
Go语言map的多键索引——多个数值条件可以同时查询
xyz
于 2021-09-02 23:40:50 发布
1277
收藏
分类专栏:
GoLang
文章标签:
go
原文链接:https://mp.csdn.net/mp_blog/creation/editor
版权
GoLang
专栏收录该内容
131 篇文章
9 订阅
订阅专栏
在大多数的编程语言中,映射容器的键必须以单一值存在。这种映射方法经常被用在诸如信息检索上,如根据通讯簿的名字进行检索。但随着查询条件越来越复杂,检索也会变得越发困难。下面例子中涉及通讯簿的结构,结构如下:
// 人员档案type Profile struct {Name string // 名字Age int // 年龄Married bool // 已婚}
并且准备好了一堆原始数据,需要算法实现构建索引和查询的过程,代码如下:
func main() {list := []*Profile{{Name: "张三", Age: 30, Married: true},{Name: "李四", Age: 21},{Name: "王麻子", Age: 21},}buildIndex(list)queryData("张三", 30)}
需要用算法实现 buildIndex() 构建索引函数及 queryData() 查询数据函数,查询到结果后将数据打印出来。 下面,分别基于传统的基于哈希值的多键索引和利用 map 特性的多键索引进行查询。
基于哈希值的多键索引及查询
传统的数据索引过程是将输入的数据做特征值。这种特征值有几种常见做法:
将特征使用某种算法转为整数,即哈希值,使用整型值做索引。将特征转为字符串,使用字符串做索引。
数据都基于特征值构建好索引后,就可以进行查询。查询时,重复这个过程,将查询条件转为特征值,使用特征值进行查询得到结果。 基于哈希的传统多键索引和查询的完整代码位于./src/chapter12/classic/classic.go,下面是对各个部分的分析。
本套教程所有源码下载地址:
https://pan.baidu.com/s/1ORFVTOLEYYqDhRzeq0zIiQ    提取密码:hfyf
1) 字符串转哈希值
本例中,查询键(classicQueryKey)的特征值需要将查询键中每一个字段转换为整型,字符串也需要转换为整型值,这里使用一种简单算法将字符串转换为需要的哈希值,代码如下:
func simpleHash(str string) (ret int) {// 遍历字符串中的每一个ASCII字符for i := 0; i < len(str); i++ {// 取出字符c := str[i]// 将字符的ASCII码相加ret += int(c)}return}
代码说明如下:
第 1 行传入需要计算哈希值的字符串。第 4 行,根据字符串的长度,遍历这个字符串的每一个字符,以 ASCII 码为单位。第 9 行,c 变量的类型为 uint8,将其转为 int 类型并累加。
哈希算法有很多,这里只是选用一种大家便于理解的算法。哈希算法的选用的标准是尽量减少重复键的发生,俗称“哈希冲撞”,即同样两个字符串的哈希值重复率降到最低。
2) 查询键
有了哈希算法函数后,将哈希函数用在查询键结构中。查询键结构如下:
// 查询键type classicQueryKey struct {Name string // 要查询的名字Age int // 要查询的年龄}// 计算查询键的哈希值func (c *classicQueryKey) hash() int {// 将名字的Hash和年龄哈希合并return simpleHash(c.Name) + c.Age*1000000}
代码说明如下:
第 2 行,声明查询键的结构,查询键包含需要索引和查询的字段。第 8 行,查询键的成员方法哈希,通过调用这个方法获得整个查询键的哈希值。第 10 行,查询键哈希的计算方法:使用 simpleHash() 函数根据给定的名字字符串获得其哈希值。同时将年龄乘以 1000000 与名字哈希值相加。
哈希值构建过程如下图所示
3) 构建索引
本例需要快速查询,因此需要提前对已有的数据构建索引。前面已经准备好了数据查询键,使用查询键获得哈希即可对数据进行快速索引,参考下面的代码:
// 创建哈希值到数据的索引关系var mapper = make(map[int][]*Profile)// 构建数据索引func buildIndex(list []*Profile) {// 遍历所有的数据for _, profile := range list {// 构建数据的查询索引key := classicQueryKey{profile.Name, profile.Age}// 计算数据的哈希值, 取出已经存在的记录existValue := mapper[key.hash()]// 将当前数据添加到已经存在的记录切片中existValue = append(existValue, profile)// 将切片重新设置到映射中mapper[key.hash()] = existValue}}
代码说明如下:
第 2 行,实例化一个 map,键类型为整型,保存哈希值;值类型为 *Profile,为通讯簿的数据格式。第 5 行,构建索引函数入口,传入数据切片。第 8 行,遍历数据切片的所有数据元素。第 11 行,使用查询键(classicQueryKey)来辅助计算哈希值,查询键需要填充两个字段,将数据中的名字和年龄赋值到查询键中进行保存。第 14 行,使用查询键的哈希方法计算查询键的哈希值。通过这个值在 mapper 索引中查找相同哈希值的数据切片集合。因为哈希函数不能保证不同数据的哈希值一定完全不同,因此要考虑在发生哈希值重复时的处理办法。第 17 行,将当前数据添加到可能存在的切片中。第 20 行,将新添加好的数据切片重新赋值到相同哈希的 mapper 中。
具体哈希结构如下图所示。
图:哈希结构
这种多键的算法就是哈希算法。map 的多个元素对应哈希的“桶”。哈希函数的选择决定桶的映射好坏,如果哈希冲撞很厉害,那么就需要将发生冲撞的相同哈希值的元素使用切片保存起来。
4) 查询逻辑
从已经构建好索引的数据中查询需要的数据流程如下:
给定查询条件(名字、年龄)。根据查询条件构建查询键。查询键生成哈希值。根据哈希值在索引中查找数据集合。遍历数据集合逐个与条件比对。获得结果。
func queryData(name string, age int) {// 根据给定查询条件构建查询键keyToQuery := classicQueryKey{name, age}// 计算查询键的哈希值并查询, 获得相同哈希值的所有结果集合resultList := mapper[keyToQuery.hash()]// 遍历结果集合for _, result := range resultList {// 与查询结果比对, 确认找到打印结果if result.Name == name && result.Age == age {fmt.Println(result)return}}// 没有查询到时, 打印结果fmt.Println("no found")}
代码说明如下:
第 1 行,查询条件(名字、年龄)。第 4 行,根据查询条件构建查询键。第 7 行,使用查询键计算哈希值,使用哈希值查询相同哈希值的所有数据集合。第 10 行,遍历所有相同哈希值的数据集合。第 13 行,将每个数据与查询条件进行比对,如果一致,表示已经找到结果,打印并返回。第 20 行,没有找到记录时,打印 no found。
利用 map 特性的多键索引及查询
使用结构体进行多键索引和查询比传统的写法更为简单,最主要的区别是无须准备哈希函数及相应的字段无须做哈希合并。看下面的实现流程。 利用map特性的多键索引和查询的代码位于./src/chapter12/multikey/multikey.go,下面是对各个部分的分析。
本套教程所有源码下载地址:
https://pan.baidu.com/s/1ORFVTOLEYYqDhRzeq0zIiQ    提取密码:hfyf
1) 构建索引
代码如下:
// 查询键type queryKey struct {Name stringAge int}// 创建查询键到数据的映射var mapper = make(map[queryKey]*Profile)// 构建查询索引func buildIndex(list []*Profile) {// 遍历所有数据for _, profile := range list {// 构建查询键key := queryKey{Name: profile.Name,Age: profile.Age,}// 保存查询键mapper[key] = profile}}
代码说明如下:
第 2 行,与基于哈希值的查询键的结构相同。第 8 行,在 map 的键类型上,直接使用了查询键结构体。注意,这里不使用查询键的指针。同时,结果只有 *Profile 类型,而不是 *Profile 切片,表示查到的结果唯一。第 17 行,类似的,使用遍历到的数据的名字和年龄构建查询键。第 23 行,更简单的,直接将查询键保存对应的数据。
2) 查询逻辑
// 根据条件查询数据func queryData(name string, age int) {// 根据查询条件构建查询键key := queryKey{name, age}// 根据键值查询数据result, ok := mapper[key]// 找到数据打印出来if ok {fmt.Println(result)} else {fmt.Println("no found")}}
代码说明如下:
第 5 行,根据查询条件(名字、年龄)构建查询键。第 8 行,直接使用查询键在 map 中查询结果。第 12 行,找到结果直接打印。第 14 行,没有找到结果打印 no found。
总结
基于哈希值的多键索引查询和利用 map 特性的多键索引查询的代码复杂程度显而易见。聪明的程序员都会利用 Go语言的特性进行快速的多键索引查询。 其实,利用 map 特性的例子中的 map 类型即便修改为下面的格式,也一样可以获得同样的结果:
var mapper = make(map[interface{}]*Profile)
代码量大大减少的关键是:Go语言的底层会为 map 的键自动构建哈希值。能够构建哈希值的类型必须是非动态类型、非指针、函数、闭包。
非动态类型:可用数组,不能用切片。非指针:每个指针数值都不同,失去哈希意义。函数、闭包不能作为 map 的键。
xyz
关注
关注
点赞
收藏
评论
Go语言map的多键索引——多个数值条件可以同时查询
在大多数的编程语言中,映射容器的键必须以单一值存在。这种映射方法经常被用在诸如信息检索上,如根据通讯簿的名字进行检索。但随着查询条件越来越复杂,检索也会变得越发困难。下面例子中涉及通讯簿的结构,结构如下:// 人员档案type Profile struct {Name string // 名字Age int // 年龄Married bool // 已婚}并且准备好了一堆原始数据,需要算法实现构建索引和查询的过程,代码如下:func main() {li
复制链接
扫一扫
专栏目录
java map 索引_一文读懂Java之HashMap索引位置计算
weixin_36156538的博客
02-13
1189
1. 前言通过前面的文章,我们知道了什么是哈希表,Java的HashMap是什么、其底层的结构以及如何使用Java里面的HashMap。总结一句话:HashMap是基于底层叫Entry[]数组实现的一种哈希表那今天我们来稍微深入一点,讲解HashMap里面的一个点:存取(put/get)数据的时候,Entry数组index下标的计算。1.1 hashCode,hash与index的概念来回忆一下:...
C++ map 遍历
weixin_33985679的博客
12-27
78
#include <iostream>
#include <map>
using namespace std;
int main(){
map<int,int> m;
for (int i = 0; i < 10; i++){
m[i] = i*i;
map<int,int&...
参与评论
您还未登录,请先
登录
后发表或查看评论
「每周译Go」​理解 Go 中的 Map
最新发布
Go中国
10-03
190
目录如何在 Ubuntu 18.04 上安装 Go 和设置本地编程环境如何在 macOS 上安装 Go 和设置本地编程环境如何在 Windows 10 上安装 Go 和设置本地编程环境如何用 Go 编写你的第一个程序理解 GOPATH如何在 Go 中写注释理解 Go 的数据类型Go 中处理字符串的介绍如何在 Go 中格式化字符串介绍 Go 中的 Strings 包如何在 Go 中使用变量和常量如何...
Go语言map的使用及详解
yanghaitao5000的博客
05-27
1261
Map是无序的键值对集合,是通过key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
package main
import "fmt"
func main() {
//定义Map,不初始化,m值为空(nil),nil map 不能用来存放键值对
var m map[string]string
fmt.Println(m, n.
Go语言的“避坑”与技巧
DXB2021的博客
03-21
78
一、合理地使用并发特性
1、了解goroutine的生命期时再创建goroutine
代码如下:
package main
import (
"fmt"
"runtime"
//一段耗时的计算函数
func consumer(ch chan int) {
//无限获取数据的循环
for {
//从通道获取数据
data := <-ch
//打印数据
fmt.Println(data)
func main() {
//创建一个传递数据用的通道
ch
Go语言学习笔记---映射(map)的基本使用
suoyudong的博客
03-22
126
map—建立事务关联的容器
应用场景:需要使用任意类型的关联关系时,需要用到映射。如学号和学生,名字与档案。
底层实现:使用散列表实现。
散列表实现,所以查找时间复杂度为O(1),最坏情况为O(n),n为元素总数。
1.添加关联map并访问关联和数据。
定义:
map[keyType]ValueType
示例:
m := map[string]string{
"W":"forward",
...
Golang map的多键索引
weixin_42117918的博客
05-20
4111
在大多数的编程语言中,映射容器的键必须以单一值存在。这种映射方法经常被用在诸如信息索引上,如根据通讯簿的名字进行检索。但随着查询条件越来越复杂,检索也会变得越发困难。
代码示例:
package main
import (
"fmt"
type queryKey struct {
Name string
Age int
type Profile struct {
Name...
开发日记之go当中的map查找
KO_NO_JOJO的博客
12-04
825
在golang当中不会触发panic,因为它会额外返回一个bool类型的元素表示元素是否查找到。所以可以同时用两个变量去接收,如果第二个变量为True的话,就说明查找成功了。
进一步,还可以将这个逻辑和if的初始化操作合在一起:
if val,ok:=m["123"];ok{
fmt.Println(val)
这里的ok就表示查找是否成功
...
go map增删改查及互换操作整理
空山新雨后,天气晚来秋
01-01
1923
go map 是一种无序的键值对集合,今天复习一下map结构及其操作,扎实下基础。
江山如此多娇,引无数英雄竞折腰。
目录
map元素查看、遍历与删除
map元素修改(元素value类型为string、int)
map元素修改(元素value类型为struct{})
k-v互换操作
map元素查看、遍历与删除
// 初始化一个string值的map并赋值
m := map[...
golang map多维key获取值
nakeer的博客
06-22
814
有时候需要获取一个多维map中某个key的值,只能用.(map[string]interface{})慢慢强转换以后来取,太多的话就麻烦了。因此我写了一个多维map的取值函数,类似于PHP中的多维关联数组。
函数如下:
import (
"encoding/json"
"errors"
//MapGetValue map[string]interface{}获取值,支持多维
func MapGetValue(keys []string, data map[string]interface{}
11 Go语言的映射——map
weixin_33884611的博客
03-04
64
Go语言的映射——map
[TOC]
类似其它语言中的哈希表或者字典,以key-value形式存储数据
Key必须是支持==或!=比较运算的类型,不可以是函数、map或slice;value 可以是任意类型。
Map查找比线性搜索快很多,但比使用索引访问数据的类型慢100倍
Map使用make()创 建,支持 := 这种简写方式
mak...
go语言map的复杂用法
热门推荐
初夏的专栏
03-12
1万+
// 对于简的map 例如 map[string] string 还是很好掌握的
// 下面这个程序演示复杂的map
package main
import "fmt"
type PersonInfo struct {
ID string
Name string
Address string
func main() {
Go语言基础:map|函数
Zeker62的博客
10-19
743
文章目录mapmap的定义map使用判断某个键是否存在map的遍历使用delete函数删除键值对特定的顺序遍历map元素是map类型的切片元素类型是切片的map练习函数函数定义函数的调用参数类型的简写可变参数返回值多返回值返回值命名返回值补充变量作用域全局变量局部变量函数类型与变量定义函数类型函数类型变量使用高级用法函数作为参数函数作为返回值匿名函数
map
map类似与python中的字典,由键值对构成
Go语言中的map是引用类型,必须初始化才能使用。
map的定义
Go语言中 map的定义语法如下:
Go 语言 map源码分析及图解(一)(查找、写入、删除K/V值)
qq_24447809的博客
04-18
520
map基本结构
hmap是map的核心数据结构:
type hmap struct {
count int // 当前的元素个数
flags uint8
B uint8 // 桶的数量为2的B次方,方便进行哈希的与运算
noverflow uint16 // 溢出桶的数量
hash0 uint32 // 哈希种子,计算哈希值使用
buckets unsafe.Pointer // 桶的数量,为2的B次方
oldbuckets unsafe.Po
Go语言实现一键多值的Map
liutianjia2014的博客
07-20
2845
照着源码,实现了Go语言,一键多值的Map
package main
type Multimap map[string][]string
type keyValues struct {
key string
values []string
func (multimap Multimap) Add(key, value string) {
Kotlin 基础——Map集合详解
一名互联网时代苟且偷生的 Android码农
04-13
4860
Kotlin基础——Map集合详解一、声明和创建Map集合二、使用Map的方法三、遍历Map四种方式四、可变的Map
Kotlin的Map集合用于保存key-value对,其也被分为可变的和不可变的。
一、声明和创建Map集合
Kotlin提供了如下函数来创建Map集合:
mapOf():该函数返回不可变的Map集合。该函数可接受0个或多个key-value对,这些key-value对将作为Ma...
golang:map的多键索引
OceanStar的博客
03-31
2357
if _, ok := map[key]; ok {
//存在
原文:https://blog.csdn.net/xielingyun/article/details/49996247
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
©️2022 CSDN
皮肤主题:猿与汪的秘密
设计师:我叫白小胖
返回首页
xyz
CSDN认证博客专家
CSDN认证企业博客
码龄23年
暂无认证
76
原创
2万+
周排名
97万+
总排名
15万+
访问
等级
1653
积分
25
粉丝
39
获赞
评论
210
收藏
私信
关注
热门文章
Dockerfile CMD 命令详解
20304
Linux 打包压缩-文件打包-打包工具【tar】命令使用简介
6512
Linux 如何杀死一个进程和它的所有子进程
5137
Java java.awt.headless=true 的具体作用
4537
如何检测MySQL是否命中索引?
4090
分类专栏
笔记
LeetCode
1篇
Computer
1篇
Thinking
2篇
DevOps
1篇
Keep Effective保持高效
1篇
Linux
109篇
Linux Shell
14篇
Linux 计划任务
2篇
Linux 内存管理
Linux 网络安全
Linux 网络服务器
Linux 网络通讯
Linux 软件管理
9篇
Linux 进程与作业管理
15篇
Linux 磁盘管理
14篇
Linux 系统安全
2篇
Linux 系统管理
8篇
Linux 文件管理
44篇
Linux 用户和工作组管理
11篇
Linux 硬件管理
2篇
Linux 内核管理
Linux 性能检测优化
Linux 打印命令
Linux 文件传输
虚拟化
1篇
Linux 打包压缩
6篇
vmware
1篇
OpenStack
Java
64篇
事务控制
2篇
JVM
6篇
Exception
Spring
2篇
Logging
webserver
2篇
SQL
7篇
多线程
31篇
Spring Cloud Alibaba
1篇
SpringBoot
定时器
1篇
SpringCloud
1篇
RocketMQ
1篇
CodingTime
1篇
GoLang
131篇
Rancher
4篇
Kubernetes
Docker
8篇
DockerImage
DockerFile
2篇
Docker Drivers
Docker API
Docker Compose
Docker Source Code
Docker Command Line
1篇
Jenkins
7篇
Redis
1篇
Nexus
1篇
Maven
2篇
Git
4篇
最新评论
rancher 在启动jenkins的时候,往jenkins所在的容器写入hosts文件,应对jenkins中需要使用外部部署的服务,例如局域网里的harbor
xyz:
已经再次遇到了该问题,已经成功解决了,docker run --hosts是可以增加ip的,或者可以在pipeline里增加一个shell脚本,类似:echo 'harbor.xxx.com 192.168.10.22 >> /etc/hosts'来解决
Go语言将秒转换为具体的时间
经典老哥:
你这计算时分的时候是错的,得先取余然后再除
Go语言-【结构体】-方法和接收器
m0_61585431:
谢谢解惑
Linux 如何杀死一个进程和它的所有子进程
Binx จุ๊บ:
写的很好,所以最后 nohup 启动的一系列子进程还是要一个一个杀掉啊
Go语言-【结构体】-将结构体数据保存为JSON格式数据
未名湖畔种千玺:
别搬了行吗,写完你自己不看看吗,一点价值都没有
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
golang高并发模型
Go语言CSP:通信顺序进程简述
Go语言封装qsort快速排序函数
2021年325篇
2020年10篇
2019年3篇
2018年7篇
目录
目录
分类专栏
笔记
LeetCode
1篇
Computer
1篇
Thinking
2篇
DevOps
1篇
Keep Effective保持高效
1篇
Linux
109篇
Linux Shell
14篇
Linux 计划任务
2篇
Linux 内存管理
Linux 网络安全
Linux 网络服务器
Linux 网络通讯
Linux 软件管理
9篇
Linux 进程与作业管理
15篇
Linux 磁盘管理
14篇
Linux 系统安全
2篇
Linux 系统管理
8篇
Linux 文件管理
44篇
Linux 用户和工作组管理
11篇
Linux 硬件管理
2篇
Linux 内核管理
Linux 性能检测优化
Linux 打印命令
Linux 文件传输
虚拟化
1篇
Linux 打包压缩
6篇
vmware
1篇
OpenStack
Java
64篇
事务控制
2篇
JVM
6篇
Exception
Spring
2篇
Logging
webserver
2篇
SQL
7篇
多线程
31篇
Spring Cloud Alibaba
1篇
SpringBoot
定时器
1篇
SpringCloud
1篇
RocketMQ
1篇
CodingTime
1篇
GoLang
131篇
Rancher
4篇
Kubernetes
Docker
8篇
DockerImage
DockerFile
2篇
Docker Drivers
Docker API
Docker Compose
Docker Source Code
Docker Command Line
1篇
Jenkins
7篇
Redis
1篇
Nexus
1篇
Maven
2篇
Git
4篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值