golang 如何获取map所有key的方式

最佳方式:根据map的长度,新建一个数组,遍历map逐个压入

方法1(效率很高):

func getKeys1(m map[int]int) []int {
 // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
 j := 0
 keys := make([]int, len(m))
 for k := range m {
  keys[j] = k
  j++
 }
 return keys
}

方法2(效率很高):

func getKeys2(m map[int]int) []int {
 // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
 keys := make([]int, 0, len(m))
 for k := range m {
  keys = append(keys, k)
 }
 return keys
}

其他方式:

方法3(效率较低):

func getKeys3(m map[int]int) []int {
 // 注意:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低
 keys := []int{}
 for k := range m {
  keys = append(keys, k)
 }
 return keys
}

方法4(效率极低):

func getKeys4(m map[int]int) int {
 // 注意:虽然此写法简洁,但MapKeys函数内部操作复杂,效率极低
 keys := reflect.ValueOf(m).MapKeys()
 return len(keys)
}

实验结果如图(可以看到方法1和方法2效率最高,内存操作也最少):

完整代码如下:

package test

import (
 "reflect"
 "testing"
)

// 初始化map
func initMap() map[int]int {
 m := map[int]int{}
 for i := 0; i < 10000; i++ {
  m[i] = i
 }
 return m
}

func getKeys1(m map[int]int) []int {
 // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
 j := 0
 keys := make([]int, len(m))
 for k := range m {
  keys[j] = k
  j++
 }
 return keys
}

func getKeys2(m map[int]int) []int {
 // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
 keys := make([]int, 0, len(m))
 for k := range m {
  keys = append(keys, k)
 }
 return keys
}

// 初始化默认
func getKeys3(m map[int]int) []int {
 // 注意:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低
 keys := []int{}
 for k := range m {
  keys = append(keys, k)
 }
 return keys
}

// 使用反射
func getKeys4(m map[int]int) int {
 // 注意:虽然此写法简洁,但MapKeys函数内部操作复杂,效率极低
 keys := reflect.ValueOf(m).MapKeys()
 return len(keys)
}

func BenchmarkMapkeys1(b *testing.B) {
 // 初始化map
 m := initMap()

 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  getKeys1(m)
 }
}
func BenchmarkMapkeys2(b *testing.B) {
 // 初始化map
 m := initMap()

 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  getKeys2(m)
 }
}

func BenchmarkMapkeys3(b *testing.B) {
 // 初始化map
 m := initMap()

 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  getKeys3(m)
 }
}

func BenchmarkMapkeys4(b *testing.B) {
 // 初始化map
 m := initMap()

 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  getKeys4(m)
 }
}

补充:Golang踩坑——判断map中是否有key

最近在实习,下班回去十点多了,再加上比较懒,快有两个月没写东西了。

今天在开发一个模块的时候是接着上一个人的写的,好不容易各种配置写好了开始跑,发现他踩了一个很容易踩的坑。

把bug抽出来单独写了个文件

package main

import (
	"log"
)

type agent struct {
	id  int
	str string
}

var m map[int]*agent
func main() {
	m = make(map[int]*agent)
	a := &agent{
		id:  1,
		str: "hello",
	}
	log.Println(a)
	var ok bool
	if a, ok = m[1]; ok {
		log.Println("ok")
	}
	m[1] = a
	log.Println(a)
	log.Println(a.str)
}

运行一下

可以看到报了无效指针的问题(invalid memory address or nil pointer dereference)。

从上面的两个log可以看到,最开始指针是有值的,第二个却没了,原因就出现在那个if判断那里。

if判断是想通过查看map知道agent是否已经存在,这个地方的错误是a,ok = map; 我们想通过ok判断是否存在,但是在这里还有个a,这会导致有一个对a赋值的操作,也就是说如果map里有这个值,那没事,如果没有的话a就被赋值成了nil了。

在下面打印的时候也就成了nil,取它的属性的时候会告诉我们找了个空指针的属性,这肯定找不到。

我们把a换成_,再来看结果:

ok了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • golang interface判断为空nil的实现代码

    要判断interface 空的问题,首先看下其底层实现. interface 底层结构 根据 interface 是否包含有 method,底层实现上用两种 struct 来表示:iface 和 eface.eface表示不含 method 的 interface 结构,或者叫 empty interface. 对于 Golang 中的大部分数据类型都可以抽象出来 _type 结构,同时针对不同的类型还会有一些其他信息. 1.eface type eface struct { _type *_t

  • 详解用Go语言实现工厂模式(Golang经典编程案例)

    golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题.这个模式本身很简单而且使用在业务较简单的情况下.一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改). 代码结构如下:分别有main.go和student.go两个文件. 在student.go中: package model //定义一个结构体 type student struct{ Name string score float64 } //因为student结构体首字母是小写,因此是只能在mod

  • golang判断key是否在map中的代码

    个人常用函数 func IsContain(items []string, item string) bool { for _, eachItem := range items { if eachItem == item { return true } } return false } 使用方法 var word := "my" var sentence := []string{"my","word","in","a

  • 深入Golang中的sync.Pool详解

    我们通常用golang来构建高并发场景下的应用,但是由于golang内建的GC机制会影响应用的性能,为了减少GC,golang提供了对象重用的机制,也就是sync.Pool对象池. sync.Pool是可伸缩的,并发安全的.其大小仅受限于内存的大小,可以被看作是一个存放可重用对象的值的容器. 设计的目的是存放已经分配的但是暂时不用的对象,在需要用到的时候直接从pool中取. 任何存放区其中的值可以在任何时候被删除而不通知,在高负载下可以动态的扩容,在不活跃时对象池会收缩. sync.Pool首先

  • 解决golang 反射interface{}做零值判断的一个重大坑

    在对float零值判断时往往只需要和0做==即可,所以曾经int和float都用==0来做对比, 比如下方: in := 0. var tmp interface{} = float32(in) fmt.Println("float 0==0:", in == 0) fmt.Println("float -> interface{} -> float", tmp.(float32) == 0) switch v := tmp.(type) { case

  • Golang 实现interface类型转string类型

    看代码吧~ // Strval 获取变量的字符串值 // 浮点型 3.0将会转换成字符串3, "3" // 非数值或字符类型的变量将会被转换成JSON格式字符串 func Strval(value interface{}) string { var key string if value == nil { return key } switch value.(type) { case float64: ft := value.(float64) key = strconv.Format

  • golang通过反射设置结构体变量的值

    如果需要动态设置struct变量field的情况下, 可以利用reflect来完成. 代码如下: package main import ( "fmt" "reflect" ) // 定义结构体Person type Person struct { Name string Age int } func main() { person := Person{} fmt.Println(person) // 修改前 { 0} pp := reflect.ValueOf(&

  • golang 如何获取map所有key的方式

    最佳方式:根据map的长度,新建一个数组,遍历map逐个压入 方法1(效率很高): func getKeys1(m map[int]int) []int { // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高 j := 0 keys := make([]int, len(m)) for k := range m { keys[j] = k j++ } return keys } 方法2(效率很高): func getKeys2(m map[int]int) [

  • 详解JAVA里面获取map的key和value的方法

    获取map的key和value的方法分为两种形式: map.keySet():先获取map的key,然后根据key获取对应的value: map..entrySet():同时查询map的key和value,只需要查询一次. 同时遍历key和value时,keySet与entrySet方法的性能差异取决于key的具体情况,如复杂度(复杂对象).离散度.冲突率等.换言之,取决于HashMap查找value的开销.entrySet一次性取出所有key和value的操作是有性能开销的,当这个损失小于Ha

  • JS代码如何获取map的key

    目录 JS获取map的key JS map根据value获取key 测试数据 根据key获取value 根据value获取key JS获取map的key Object.keys(map) //获取回来集合大家可以试一下 JS map根据value获取key 前端通过对象保存字典值用于列表字段翻译或者加载下拉框都是很常见的操作,有时也会需要根据字典值的value获取对应的key,搜了下相关的文章比较少,在此记录下. 测试数据 paramsMap: { orderType: { '0': '咨询',

  • golang 并发安全Map以及分段锁的实现方法

    涉及概念 并发安全Map 分段锁 sync.Map CAS ( Compare And Swap ) 双检查 分断锁 type SimpleCache struct { mu sync.RWMutex items map[interface{}]*simpleItem } 在日常开发中, 上述这种数据结构肯定不少见,因为golang的原生map是非并发安全的,所以为了保证map的并发安全,最简单的方式就是给map加锁. 之前使用过两个本地内存缓存的开源库, gcache, cache2go,其中

  • Java遍历Map键、值和获取Map大小的方法示例

    Map读取键值对,Java遍历Map的两种实现方法 第一种方法是根据map的keyset()方法来获取key的set集合,然后遍历map取得value的值 import java.util.HashMap; import java.util.Iterator; import java.util.Set; public class HashMapTest2 { public static void main(String[] args) { HashMap map = new HashMap();

  • spring+apollo动态获取yaml格式的配置方式

    默认spring装载的都是.properties格式的配置文件,但是有时我们需要定义list或者map类型的配置,那么yaml就具有优势. 以下演示利用apollo来完成自动更新ip白名单的功能 1.重写配置工厂 public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { public PropertySource<?> createPropertySource(String name, Encode

  • java迭代器原理及迭代map的四种方式

    目录 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器怎么实现的? 迭代器的陷阱? 为什么会产生这样的错误? 遍历map的四种方式 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器就是用来遍历集合中对象的东西,也就是说,对于集合,我们不像对原始数组那样通过直接访问元素来迭代的,而是通过迭代器来遍历对象.这么做的好处是将对于集合类型的遍历行为与被遍历集合对象分离,这样以来,就不需要关心该集合类型的具体实现是怎么样的.只要获取这个集合对象的迭代器便可以遍历这个集合中的对象.而像遍历对象顺

  • Golang通脉之map详情

    目录 1.定义 2.基本使用 3.判断键是否存在 4.map的遍历 5.delete()函数删除map元素 6.指定顺序遍历map 7.map类型的切片 8.value为切片类型的map 9.map是引用类型 Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现. map 是一种无序的键值对的集合.map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值 map 是一种集合,所以可以像迭代数组和切片那样迭代它.不过,map 是无序的,无法决定它的返回

  • Golang反射获取变量类型和值的方法详解

    目录 1. 什么是反射 2. reflect.Type 2.1 类型Type和种类Kind 2.2 引用指向元素的类型 2.3 结构体成员类型 3. reflect.Value 3.1 结构体的成员的值 3.2 遍历array.slice 3.3 遍历map 4. 反射的三大定律 4.1 从interface到反射对象 4.2 从反射对象到interface 4.3 通过反射修改对象,该对象值必须是可修改的 1. 什么是反射 反射是程序在运行期间获取变量的类型和值.或者执行变量的方法的能力. G

  • 详解iOS获取通讯录的4种方式

    本文实例为大家分享了iOS获取通讯录的4种方式,供大家参考,具体内容如下 使用场景 一些App通过手机号码来推荐好友,如 微博.支付宝 首先客户端会获取通讯录中的所有手机号然后将这些手机号提交到App服务器中,服务器会查找每个手机号对应的App账号如QQ号码返回到客户端,然后客户端根据服务器返回的账号列表来推荐好友. 获取联系人方式 方案一:AddressBookUI.framework框架 提供了联系人列表界面.联系人详情界面.添加联系人界面等 一般用于选择联系人 方案二:AddressBoo

随机推荐