map概述
哈希表是一种巧妙并且使用的数据结构。它是一个无序的key-value
对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。
Golang中,一个map就是一个哈希表的引用,又称为字段或者关联数组。类似其他编程语言的集合,在编程中是经常使用到。
map的声明
基本语法
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。
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是无序的
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"])
map的增删改查操作
map增加和更新
map["key"] = value //如果key还没有,就是增加,如果key存在就是修改
删除
删除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])
}
查找
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))
}
遍历
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\n", 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("\tkey2=%v value2=%v\n", 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
}
map切片
基本介绍
切片的数据类型如果是map,则称为slice of map(map切片),这样map的个数就可以动态变化。
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]]
}
map排序
基本介绍
Golang中没有一个专门的方法或者函数针对map的key进行排序。Golang中的map默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的输出可能不一样。
map排序方法:先将key进行排序,然后根据key值遍历输出即可
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])
}
}
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}]
}
练习
- 使用
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\n", s)
m["q1mi"] = s
s = append(s[:1], s[2:]...)
fmt.Printf("%+v\n", s)
fmt.Printf("%+v\n", m["q1mi"])
}