11、映射-GOLANG

概念

数组和映射使用序列整数作为索引查找指定元素的方式在针对某些特定元素的时候查找数据比较麻烦,而映射采用键值对的的方式存储数据,利用键去寻找指定的元素,而键的类型可以试几乎所有的类型

声明映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {

temperature := map[string]int{ //定义一个map存放星球表面的温度
"Earth": 15,
"Mars": -65,
}
temp := temperature["Earth"]
fmt.Println("地球表面温度为", temp, "度")
temperature["Earth"] = 16
fmt.Println(temperature)
Venus := temperature["Venus"]//与数组切片不同的是当访问映射不存在的索引时,map会根据数据类型返回相应的零值作为结果
fmt.Println(Venus)

}

上面的写法可能会存在某些问题,比如我如何判断Venus真的存在于map中并且数值就是0,还是说不存在,map返回了零值,这种情况go语言提供了”逗号与ok”语法进行判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func main() {

temperature := map[string]int{ //定义一个map存放星球表面的温度
"Earth": 15,
"Mars": -65,
}
temp := temperature["Earth"]
fmt.Println("地球表面温度为", temp, "度")
temperature["Earth"] = 16
fmt.Println(temperature)
Venus := temperature["Venus"]
fmt.Println(Venus)
if Venus, t := temperature["Venus"]; t {//t可以更换为你自定义的变量名称,Venus存在时t为true,不存在时为false
fmt.Println("金星表面温度为", Venus, "度")
} else {
fmt.Println("金星搁哪呢")//Venus不存在时输出这句话
}

}

image-20230310080004248

映射不会被复制

数组在赋值给新变量的时候会复制相关元素到新的内存空间,而map赋值给新的变量他俩指向的还是同一块内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import "fmt"

func main() {
dwarfs := [5]string{ //注意这是一个数组
"Ceres",
"Pluto",
"Haumea",
"Makemake",
"Eris",
}
dwarfs1 := dwarfs
dwarfs1[0] = "test"
fmt.Println(dwarfs)//原有数组数值不变
fmt.Println(dwarfs1)

temperature := map[string]int{
"Earth": 15,
"Mars": -65,
}
temp := temperature
temp["Earth"] = 25
fmt.Println(temperature)//原有map数值发生改变
fmt.Println(temp)
}

image-20230310081031477

使用make对映射进行预分配

1
temperature := make(map[string]int,8)

使用映射进行计数

定义一个存放温度的切片,利用map进行计数,需要注意的是go在迭代映射的时候不保证键的顺序,所以各位代码运行结果只要正确,键值对顺序无所谓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {

temperatures := []float64{ //声明一个切片存放温度
-28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
}
frequency := make(map[float64]int)
for _, i := range temperatures { //for _键,i值:=range temperatures
frequency[i]++ //i是temperatures切片的值把i作为frequency映射的键,也就是温度会成为键,frequency[i]的值都是int类型的零值,也就0,当遍历到某个温度第一遍时0++变成1,当这个温度再次出现时值又会再次+1实现计数
}
fmt.Println(frequency)
for t, num := range frequency {
fmt.Printf("%f 出现%d次\n", t, num)
}
}

image-20230310084341530

使用映射和切片实现数据分组

以10度为一组划分温度属于哪个组,比如负二十度的一组,负三十度的一组,三十度的一度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"math"
)

func main() {
temperatures := []float64{
-28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
}
groups := make(map[float64][]float64) //创建一个键为float64类型,而值为float64切片类型的映射
for _, t := range temperatures {
g := math.Trunc(t/10) * 10 //trunc函数用于对浮点数取整,返回浮点数的整数部分
groups[g] = append(groups[g], t)//groups[g]取出的是groups映射的值,类型为切片,所以可以用append追加元素
//举个栗子。-28被遍历以后,这句代码就变成了groups[-20] = append(groups[-20], -28)
//-23被遍历以后,这句代码就变成了groups[-20] = append(groups[-20], -23)
//32被遍历以后,这句代码就变成了groups[30] = append(groups[30], 32)
}
fmt.Println(groups)

for g, t := range groups {
fmt.Printf("%v:%v\n", g, t)
}

}

将映射用作集合

集合是一种与数组类似但是集合中的元素只会出现一次,go语言没有直接提供集合收集器,所以我们利用映射拼凑一个集合

通过集合判断温度是否存在于相关映射中,并且映射中的值是否为true,最后创建一个切片吧温度数据存进去调用sort包的函数进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"sort"
)

func main() {
temperatures := []float64{
-28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
}
set := make(map[float64]bool)
for _, t := range temperatures {
set[t] = true
}
if set[-28.0] {
fmt.Println("set member")
}
fmt.Println(set)
unique := make([]float64, 0, len(set))
for i := range set {
unique = append(unique, i)
}
sort.Float64s(unique)
fmt.Println(unique)
}