脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - GoFrame gmap遍历hashmap listmap treemap使用技巧

GoFrame gmap遍历hashmap listmap treemap使用技巧

2022-10-18 11:14王中阳Go Golang

这篇文章主要为大家介绍了GoFrame gmap遍历hashmap listmap treemap使用技巧的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

文章比较硬核,爆肝2千多字,除了hashmap、listmap、treemap使用技巧阅读还有使用gmap的踩坑之旅,阅读大约需要5~10分钟。

先说结论

map类型

一图胜千言:

GoFrame gmap遍历hashmap listmap treemap使用技巧

实例化示例:

   hashMap := gmap.New(true)
 listMap := gmap.NewListMap(true)
 treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)

使用技巧

当我们对返回顺序有要求时不能使用hashmap,因为hashmap返回的是无序列表;

当需要按输入顺序返回结果时使用listmap;

当需要让返回结果自然升序排列时使用treemap

package main
import (
 "fmt"
 "github.com/gogf/gf/container/gmap"
 "github.com/gogf/gf/frame/g"
 "github.com/gogf/gf/util/gutil"
)
func main() {
 array := g.Slice{5, 1, 2, 7, 3, 9, 0}
 hashMap := gmap.New(true)
 listMap := gmap.NewListMap(true)
 treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
 // 赋值
 for _, v := range array {
    hashMap.Set(v, v)
    listMap.Set(v, v)
    treeMap.Set(v, v)
 }
 //打印结果
 fmt.Println("hashMap.Keys()  :", hashMap.Keys())
 fmt.Println("hashMap.Values():", hashMap.Values())
 //从打印结果可知hashmap的键列表和值列表返回值的顺序没有规律,随机返回
 fmt.Println("listMap.Keys()  :", listMap.Keys())
 fmt.Println("listMap.Values():", listMap.Values())
 //listmap键列表和值列表有序返回,且顺序和写入顺序一致
 fmt.Println("treeMap.Keys()  :", treeMap.Keys())
 fmt.Println("treeMap.Values():", treeMap.Values())
 //treemap键列表和值列表也有序返回,但是不和写入顺序一致,按自然数升序返回
}

打印结果

hashMap.Keys()  : [5 1 2 7 3 9 0]
hashMap.Values(): [2 7 3 9 0 5 1]
listMap.Keys()  : [5 1 2 7 3 9 0]
listMap.Values(): [5 1 2 7 3 9 0]
treeMap.Keys()  : [0 1 2 3 5 7 9]
treeMap.Values(): [0 1 2 3 5 7 9]

为了让大家更好的理解gmap,下面介绍一下gmap的基础使用和一些进阶技巧。

 

基础概念

GoFrame框架(下文简称gf)提供的数据类型,比如:字典gmap、数组garray、集合gset、队列gqueue、树形结构gtree、链表glist都是支持设置并发安全开关的。

支持设置并发安全开关这也是gf提供的常用数据类型和原生数据类型非常重要的区别

今天和大家分享gf框架中gmap相关知识点

对比sync.Map

go语言提供的原生map不是并发安全的map类型

go语言从1.9版本开始引入了并发安全的sync.Map,但gmap比较于标准库的sync.Map性能更加优异,并且功能更加丰富。

 

基础使用

  • gmap.New(true) 在初始化的时候开启并发安全开关
  • 通过 Set() 方法赋值,通过 Sets() 方法批量赋值
  • 通过 Size() 方法获取map大小
  • 通过 Get() 根据key获取value值
  • ...

为了方便大家更好的查看效果,在下方代码段中标明了打印结果

package main
import (
 "fmt"
 "github.com/gogf/gf/container/gmap"
)
func main() {
 m := gmap.New(true)
 // 设置键值对
 for i := 0; i < 10; i++ {
    m.Set(i, i)
 }
 fmt.Println("查询map大小:", m.Size())
 //批量设置键值对
 m.Sets(map[interface{}]interface{}{
    10: 10,
    11: 11,
 })
 // 目前map的值
 fmt.Println("目前map的值:", m)
 fmt.Println("查询是否存在键值对:", m.Contains(1))
 fmt.Println("根据key获得value:", m.Get(1))
 fmt.Println("删除数据", m.Remove(1))
 //删除多组数据
 fmt.Println("删除前的map大小:", m.Size())
 m.Removes([]interface{}{2, 3})
 fmt.Println("删除后的map大小:", m.Size())
 //当前键名列表
 fmt.Println("键名列表:", m.Keys())   //我们发现是无序列表
 fmt.Println("键值列表:", m.Values()) //我们发现也是无序列表
 //查询键名,当键值不存在时写入默认值
 fmt.Println(m.GetOrSet(20, 20))   //返回值是20
 fmt.Println(m.GetOrSet(20, "二十")) //返回值仍然是20,因为key对应的值存在
 m.Remove(20)
 fmt.Println(m.GetOrSet(20, "二十")) //返回值是二十,因为key对应的值不存在
 // 遍历map
 m.Iterator(func(k interface{}, v interface{}) bool {
    fmt.Printf("%v:%v \n", k, v)
    return true
 })
 //自定义写锁操作
 m.LockFunc(func(m map[interface{}]interface{}) {
    m[88] = 88
 })
 // 自定义读锁操作
 m.RLockFunc(func(m map[interface{}]interface{}) {
    fmt.Println("m[88]:", m[88])
 })
 // 清空map
 m.Clear()
 //判断map是否为空
 fmt.Println("m.IsEmpty():", m.IsEmpty())
}

运行结果

GoFrame gmap遍历hashmap listmap treemap使用技巧

上面介绍的基础使用比较简单,下面介绍进阶使用。

合并 merge

注意:Merge()的参数需要是map的引用类型,也就是传map的取址符。

package main
import (
 "fmt"
 "github.com/gogf/gf/container/gmap"
)
func main() {
 var m1, m2 gmap.Map
 m1.Set("k1", "v1")
 m2.Set("k2", "v2")
 m1.Merge(&m2)
 fmt.Println("m1.Map()", m1.Map()) //m1.Map() map[k1:v1 k2:v2]
 fmt.Println("m2.Map()", m2.Map()) //m2.Map() map[k2:v2]
}

序列化

正如上一篇 GoFrame glist 基础使用和自定义遍历 介绍的,gf框架提供的数据类型不仅支持设置并发安全,也都支持序列化和反序列化。

json序列化和反序列化:序列化就是转成json格式,反序列化就是json转成其他格式类型(比如:map、数组、对象等)

package main
import (
 "encoding/json"
 "fmt"
 "github.com/gogf/gf/container/gmap"
)
func main() {
 // 序列化
 //var m gmap.Map
 m := gmap.New() //必须实例化 只是像上面声明但是不进行实例化,是无法序列化成功的
 m.Sets(map[interface{}]interface{}{
    "name": "王中阳",
    "age":  28,
 })
 res, _ := json.Marshal(m)
 fmt.Println("序列化结果:", res) //打印结果:{"age":28,"name":"王中阳"}
 // 反序列化
 m2 := gmap.New()
 s := []byte(`{"age":28,"name":"王中阳"}`)
 _ = json.Unmarshal(s, &m2)
 fmt.Println("反序列化结果:", m2.Map()) //反序列化结果: map[age:28 name:王中阳]
}

踩坑

正如上面代码段中注释提到的:

在进行序列化操作时,必须实例化map

m := gmap.New() 

GoFrame gmap遍历hashmap listmap treemap使用技巧

只是声明map而不进行实例化,是无法序列化成功的

var m gmap.Map

GoFrame gmap遍历hashmap listmap treemap使用技巧

过滤空值

package main
import (
 "fmt"
 "github.com/gogf/gf/container/gmap"
)
func main() {
 //首先明确:空值和nil是不一样的,nil是未定义;而空值包括空字符串,false、0等
 m1 := gmap.NewFrom(map[interface{}]interface{}{
    "k1": "",
    "k2": nil,
    "k3": 0,
    "k4": false,
    "k5": 1,
 })
 m2 := gmap.NewFrom(map[interface{}]interface{}{
    "k1": "",
    "k2": nil,
    "k3": 0,
    "k4": false,
    "k5": 1,
 })
 m1.FilterEmpty()
 m2.FilterNil()
 fmt.Println("m1.FilterEmpty():", m1) //预测结果: k5:1
 fmt.Println("m2.FilterNil():", m2)   //预测结果:除了k2,其他都返回
 // 打印结果和预期的一致:
 //m1.FilterEmpty(): {"k5":1}
 //m2.FilterNil(): {"k1":"","k3":0,"k4":false,"k5":1}
}

打印结果

m1.FilterEmpty(): {"k5":1}
m2.FilterNil(): {"k1":"","k3":0,"k4":false,"k5":1}

键值对反转 Flip

package main
import (
 "github.com/gogf/gf/container/gmap"
 "github.com/gogf/gf/frame/g"
)
func main() {
 // 键值对反转flip
 var m gmap.Map
 m.Sets(map[interface{}]interface{}{
    "k1": "v1",
    "k2": "v2",
 })
 fmt.Println("反转前:", m.Map())
 m.Flip()
 fmt.Println("反转后:", m.Map())
}

打印结果

反转前:{
     "k1": "v1",
     "k2": "v2"
}
反转后:{
     "v1": "k1",
     "v2": "k2"
}   

出栈(随机出栈)

package main
import (
 "fmt"
 "github.com/gogf/gf/container/gmap"
)
func main() {
 //pop pops map出栈(弹栈)
 var m gmap.Map
 m.Sets(map[interface{}]interface{}{
    1: 1,
    2: 2,
    3: 3,
    4: 4,
    5: 5,
 })
 fmt.Println("m.Pop()之前:", m.Map())
 key, value := m.Pop()
 fmt.Println("key:", key)
 fmt.Println("value:", value)
 fmt.Println("m.Pop()之后:", m.Map()) //多次测试后发现是随机出栈,不能理所当然的认为按顺序出栈
 res := m.Pops(2) //参数是出栈个数
 fmt.Println("res:", res)
 fmt.Println("m.Pops之后:", m.Map()) //多次测试之后发现也是随机出栈
}

运行结果

GoFrame gmap遍历hashmap listmap treemap使用技巧

踩坑

注意:多次测试后发现是随机出栈,不能理所当然的认为按顺序出栈

总结

通过这篇文章,我们了解到:

重点消化一下map遍历时,不同map的特点:

  • 1.1 当我们对返回顺序有要求时不能使用hashmap,因为hashmap返回的是无序列表;
  • 1.2 当需要按输入顺序返回结果时使用listmap;
  • 1.3 当需要让返回结果自然升序排列时使用treemap

gmap的基础使用和进阶使用技巧:反转map、序列化、合并map、出栈等。

gf框架提供的数据结构,比如:字典gmap、数组garray、集合gset、队列gqueue、树形结构gtree、链表glist 都是支持设置并发安全开关的;而且都支持序列化和反序列化,实现了标准库json数据格式的序列化/反序列化接口。

以上就是GoFrame gmap遍历hashmap listmap treemap使用技巧的详细内容,更多关于GoFrame gmap遍历的资料请关注服务器之家其它相关文章!

原文链接:https://juejin.cn/post/7101797623484383246

延伸 · 阅读

精彩推荐
  • Golang使用client go实现自定义控制器的方法

    使用client go实现自定义控制器的方法

    本文我们来使用client-go实现一个自定义控制器,通过判断service的Annotations属性是否包含ingress/http,如果包含则创建ingress,如果不包含则不创建,对client g...

    油腻中年李大鹅8572022-10-07
  • GolangGo语言编译程序从后台运行,不出现dos窗口的操作

    Go语言编译程序从后台运行,不出现dos窗口的操作

    这篇文章主要介绍了Go语言编译程序从后台运行,不出现dos窗口的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    夏虫不可语冰12482021-05-29
  • Golang解决Golang json序列化字符串时多了\的情况

    解决Golang json序列化字符串时多了\的情况

    这篇文章主要介绍了解决Golang json序列化字符串时多了\的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    Go哥10412021-03-22
  • GolangGOLANG版的冒泡排序和快速排序分享

    GOLANG版的冒泡排序和快速排序分享

    这篇文章主要介绍了GOLANG版的冒泡排序和快速排序分享,需要的朋友可以参考下 ...

    脚本之家1962020-04-25
  • Golanggolang端口占用检测的使用

    golang端口占用检测的使用

    这篇文章主要介绍了golang端口占用检测的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随...

    csd_ct13532021-04-21
  • GolangGo语言常见哈希函数的使用

    Go语言常见哈希函数的使用

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以...

    脚本之家8092020-04-24
  • GolangGolang通过SSH执行交换机操作实现

    Golang通过SSH执行交换机操作实现

    这篇文章主要介绍了Golang通过SSH执行交换机操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...

    moakia9202020-07-20
  • Golanggolang http请求封装代码

    golang http请求封装代码

    这篇文章主要介绍了golang http请求封装代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    一名路过的小码农7282021-02-28