• Go语言基础之map


    1 map概述

    哈希表是一种巧妙并且使用的数据结构。它是一个无序的key-value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。

    Golang中,一个map就是一个哈希表的引用,又称为字段或者关联数组。类似其他编程语言的集合,在编程中是经常使用到。

    2 map的声明

    2.1 基本语法

    var map 变量名 map[keytype]valuetype
    
    • key的类型

      Golang中的map的key可以是很多种类型,比如bool,数字,string,指针,channel,还可以是接口,结构体,数组。key对应的类型必须支持==比较运算符的数据类型,所以map可以通过测试key是否相等来判断是否已经存在。

      通常key为int、string。

      注意:slice,map还有function不可以作为key,因为这几个没法用==来判断。

    • valuetype的类型

      valuetype的类型没有任何的限制

      通常为:数字(整数,浮点数),string,map,struct。

    2.2 map声明举例

    var a map[string]string
    var a map[string]int
    var a map[int]string
    var a map[string]map[string]string
    

    注意:声明是不会分配内存的,初始化需要使用make,分配内存后才能赋值和使用。内建函数make分配并初始化一个类型为切片、映射、或通道的对象。

    map声明案例演示:

    func main(){
        var a map[string]string
        a = make(map[string]string, 10)  //使用make函数给map分配数据空间
        a["no1"] = "tom"
        a["no2"] = "jerry"
        a["no3"] = "jack"
        a["no1"] = "alice"
        fmt.Println(a)
    }
    

    对上面代码的说明:

    • map在使用前一定要make

    • map的key是不能重复的。如果重复了,则以最后这个key-value为准

    • map的value是可以相同的

    • map的key-value是无序的

    3 map的使用

    方式一:

    var a map[string]string
    //在使用map前,需要先make,make的作用是给map分配数据空间
    a = make(map[string]string, 10)
    a["no1"] = "tom"
    a["no2"] = "jerry"
    a["no3"] = "jack"
    a["no1"] = "alice"
    fmt.Println(a)
    

    方式二:

    cities := make(map[string]string)
    cities["no1"] = "北京"
    cities["no2"] = "天津"
    cities["no3"] = "上海"
    fmt.Println(cities)
    

    方式三:

    heroes := map[string]string{
        "heroes1" : "钢铁侠"
        "heroes2" : "蜘蛛侠"
        "heroes3" : "绿巨人"
    }
    heroes["heroes4"] = "黑寡妇"
    fmt.Println("heroes=", heroes)
    

    案例演示:

    案例需求:存放三个学生的信息,每个学生有name和sex信息

    students := make(map[string]map[string]string, 3)
    
    //对于map要先使用make声明,students中的value也是map,所以对于每个key对应的值都需要map
    students["stu01"] = make(map[string]string, 2)
    students["stu01"]["name"] = "tom"
    students["stu01"]["sex"] = "男"
    
    students["stu02"] = make(map[string]string, 2)
    students["stu02"]["name"] = "mary"
    students["stu02"]["sex"] = "女"
    
    fmt.Println(students)
    fmt.Println(students["stu01"])
    fmt.Println(students["stu01"]["name"])
    

    4 map的增删改查操作

    4.1 map增加和更新

    map["key"] = value  //如果key还没有,就是增加,如果key存在就是修改
    

    4.2 删除

    删除map中的一个键值对,使用内置函数delete。使用方法:delete(map, "key"),如果key存在,就删除key-value,如果不存在,不操作,但也不会报错。

    cities := make(map[string]string)
    cities["no1"] = "北京"
    cities["no2"] = "天津"
    cities["no3"] = "上海"
    fmt.Println(cities)
    
    //使用delete内置函数删除cities中的键值对
    delete(cities, "no1")
    fmt.Println(cities)
    
    delete(cities, "no4")
    fmt.Println(cities)
    

    在Golang中没有一下删除整个map中的key的函数。这时可以遍历一下key逐个删除,或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收。

    //方法一:使用make,开辟一个新的map空间
    cities = make(map[string]string)
    fmt.Println(cities)
    
    //方法二:遍历key,逐个删除
    for key, _ := range cities {
        delete(cities, cities[key])
    }
    

    4.3 查找

    map的查找还是通过key来进行查找,我们可以封装一个函数,参数为key和map,返回值为bool类型;如果找到返回true,否则返回false。代码如下:

    func findRes(key string, m map[string]string) bool {
    	_, ok := m[key]		// 判断某个键是否存在
    	if ok {
    		return true
    	} else {
    		return false
    	}
    }
    
    func main() {
    	cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    	fmt.Println(cities)
    	fmt.Println(findRes("no1", cities))
    	fmt.Println(findRes("no4", cities))
    }
    
    

    4.4 遍历

    map的遍历使用使用for-range的结构遍历

    func main() {
    
    	cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    	fmt.Println(cities)
    	for k, v := range cities {
    		fmt.Printf("k=%v v=%v
    ", k, v)
    	}
    
    	//变量map的map
    	students := make(map[string]map[string]string, 3)
    
    	//对于map要先使用make声明,students中的value也是map,所以对于每个key对应的值都需要map
    	students["stu01"] = make(map[string]string, 2)
    	students["stu01"]["name"] = "tom"
    	students["stu01"]["sex"] = "男"
    
    	students["stu02"] = make(map[string]string, 2)
    	students["stu02"]["name"] = "mary"
    	students["stu02"]["sex"] = "女"
    
    	for key1, value1 := range students {
    		fmt.Println("key1=", key1)
    		for key2, value2 := range value1 {
    			fmt.Printf("	key2=%v value2=%v
    ", key2, value2)
    		}
    	}
    }
    

    使用len() 内建函数可以返回map的长度:

    func main() {
    
    	cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    	fmt.Println(cities)
    
    	//变量map的map
    	students := make(map[string]map[string]string, 3)
    
    	//对于map要先使用make声明,students中的value也是map,所以对于每个key对应的值都需要map
    	students["stu01"] = make(map[string]string, 2)
    	students["stu01"]["name"] = "tom"
    	students["stu01"]["sex"] = "男"
    
    	students["stu02"] = make(map[string]string, 2)
    	students["stu02"]["name"] = "mary"
    	students["stu02"]["sex"] = "女"
    
    	fmt.Println(len(students))		//2
    	fmt.Println(len(cities))		//3
    }
    

    5 map切片

    5.1 基本介绍

    切片的数据类型如果是map,则称为slice of map(map切片),这样map的个数就可以动态变化。

    5.2 map切片的使用

    案例演示:

    案例需求:使用一个map来记录学生的信息name和age,并且学生的个数可以动态增加

    func main() {
    	//声明一个students的map切片
    	var students []map[string]string
    	students = make([]map[string]string, 2)		//先存放两个学生
    	if students[0] == nil {
    		students[0] = make(map[string]string, 2)
    		students[0]["name"] = "tom"
    		students[0]["age"] = "24"
    	}
    	if students[1] == nil {
    		students[1] = make(map[string]string, 2)
    		students[1]["name"] = "mary"
    		students[1]["age"] = "20"
    	}
    
    	//越界panic: runtime error: index out of range [2] with length 2
    	//if students[2] == nil {
    	//	students[2] = make(map[string]string, 2)
    	//	students[2]["name"] = "jerry"
    	//	students[2]["age"] = "20"
    	//}
    
    	//使用append函数动态的增加students
    	student := map[string]string {
    		"name" : "jerry",
    		"age" : "20",
    	}
    	students = append(students, student)
    	fmt.Println(students)	//[map[age:24 name:tom] map[age:20 name:mary] map[age:20 name:jerry]]
    }
    

    6 map排序

    6.1 基本介绍

    Golang中没有一个专门的方法或者函数针对map的key进行排序。Golang中的map默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的输出可能不一样。

    map排序方法:先将key进行排序,然后根据key值遍历输出即可

    6.2 map排序演示

    func main() {
    	rand.Seed(time.Now().UnixNano())	//初始化随机种子
    	// 声明一个scoreMap用来存学生的成绩
    	var scoreMap = make(map[string]int, 200)
    
    	for i := 0; i <  100; i++ {
    		key := fmt.Sprintf("stu%02d", i)	//生成stu开头的字符串
    		scoreMap[key] = rand.Intn(100)			//生成0-100之间的随机数作为学生的成绩
    	}
    
    	var keys = make([]string, 0, 100)
    	//取出scoreMap中的key存储到[]key切片中
    	for key := range scoreMap {
    		keys = append(keys, key)
    	}
    
    	//对切片进行排序
    	sort.Strings(keys)
    
    	//使用排序好的key对scoreMap进行遍历
    	for _, k := range keys {
    		fmt.Println(k, scoreMap[k])
    	}
    }
    

    7 map使用细节

    • map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改之,则会修改原来的map

    • map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长key-value

    • map的value也经常使用struct类型,更适合管理复杂的数据

    type Stu struct {
    	name string
    	age int
    }
    
    func main() {
    	// 使用map来存储Stu结构体
    	// 学生的学号作为map的key,因为学号唯一,学生的姓名和年龄作为Stu结构体的字段
    	var stuMap = make(map[string]Stu, 10)
    	stuMap["no1"] = Stu{"tom", 19}
    	stuMap["no2"] = Stu{"jerry", 20}
    
    	fmt.Println(stuMap)		// map[no1:{tom 19} no2:{jerry 20}]
    }
    

    8 练习

    • 使用map[string]map[string]string的map类型,key表示用户名,是唯一的,不可以重复;如果这个用户名存在,就将其密码修改成"666666",如果不存在就增加这个用户的信息(nickname和密码pwd)
    • 统计一个字符串中每个单词出现的次数。比如:"how are you are you right",how=1,are=2,you=2,right=1
    • 观察下面代码,写出最终的打印结果
    func main() {
    	type Map map[string][]int
    	m := make(Map)
    	s := []int{1, 2}
    	s = append(s, 3)
    	fmt.Printf("%+v
    ", s)
    	m["q1mi"] = s
    	s = append(s[:1], s[2:]...)
    	fmt.Printf("%+v
    ", s)
    	fmt.Printf("%+v
    ", m["q1mi"])
    }
    
  • 相关阅读:
    sql语句之case when null 解决方法
    sql server分组按顺序编号(转+补充)
    非IE用window.open弹出窗口并向父窗口传值
    IE6浏览器弹出窗口,父窗口传值
    sql之储存过程与函数的区别
    sql之执行事务性语句
    c#获取与筛选对象相匹配的所有DataRow对象数组
    ?: 运算符(C# 参考)
    Mysql 5.7优化
    libcurl.a 跨平台
  • 原文地址:https://www.cnblogs.com/dabric/p/12337500.html
Copyright © 2020-2023  润新知