前言
Go语言中提供了映射关系容器为map
,类似Python中的字典。其内部使用散列表(hash)
实现、无序、为引用数据类型。
不同于Python字典之处是map的key可以为数字,在声明map时就需要指定 map中key和value的数据类型。
为什么很多语言中都有类似map这种键值对数据集合呢?因为这种数据类型最大的特点就是查找速度快。
为什么map的查询速度会特别快呢?
map之所以查询速度快是因为,它可以根据key直接找到数据存储的位置,而其他数据类型查时从前往后遍历会比较耗时。就是利用hash存储。
以上只是hash存储的基本存储模型,其他编程语言的键值对集合大多基于此基础进行优化。
map数据类型有以下3大特点:
键不能重复
键必须是可hash的(int、bool、float、srting、arry),arry中包含了不可hash元素也不可以!
键在map集合中是无序的
map声明
map的key可以是int、bool、float、srting、arry但是arry中不能出嵌套lice元素。
package main
import "fmt"
func main() {
//1.创建map的方式
//1.声明+初始化
userInfo := map[string]string{"name": "Martin", "age": "18", "e-mail": "13220198866@163.com"}
fmt.Println(userInfo)
userList := []map[string]string{map[string]string{"name": "Martin", "age": "18", "e-mail": "martin@163.com"}, map[string]string{"name": "Alex", "age": "70", "e-mail": "Alex@163.com"}}
userList = append(userList, map[string]string{"name": "zhangdaqian", "age": "188", "e-mail": "zhangdaqian@163.com"})
fmt.Println(userList)
//2.make方式
m1 := make(map[int]int, 10)
m1[0] = 0
m1[1] = 1
fmt.Println(m1)
//2.声明map用于整体赋值
var m2 map[int]int
//m2["age"]=19 无法设置值 指向nil
m2=m1
fmt.Println(m2)
//3.new用于整体赋值
m3:=new(map[int]int)
m3=&m2
fmt.Println(m3) //返回的是指针
//4.声明数组类型的map
m4:=map[[1]int]int{[1]int{1}:1,[1]int{2}:2}
m4[[1]int{3}]=3
m4[[1]int{4}]=4
fmt.Println(m4)
/*
{
[1]:1,
[2]:2,
[3]:3,
[4]:4
}
*/
for k, v := range m4 {
fmt.Println(k,v)
}
}
map的定义及基本操作
package main
import "fmt"
func main() {
//定义了1个map变量,key是sring类型、value是int类型
var m1 map[string]int
fmt.Println(m1 == nil) //还没有初始化(没有在内存中开辟空间)
//初始化:估算好map的容量,避免程序运行期间在扩容
m1 = make(map[string]int, 10)
m1["年龄"] = 18
fmt.Println(m1)
fmt.Println(m1["年龄"])
//获取不存在的key
v, ok := m1["姓名"]
if !ok {
fmt.Println("没有该key")
} else {
fmt.Println(v)
}
//直接获取不存在的key,返回对应类型的默认值
fmt.Println(m1["不存在的key"])
//遍历map的key和value
m2 := make(map[string]string, 10)
m2["姓名"] = "Martin"
m2["性别"] = "男"
for k, v := range m2 {
fmt.Println(k, v)
}
//仅遍历map的keys
for k := range m2 {
fmt.Println(k)
}
//仅遍历map的values
for _, v := range m2 {
fmt.Println(v)
}
//删除map中的key
delete(m2,"姓名")
fmt.Println(m2)
//删除map中不存在的key() no-option
delete(m1,"不存在的key")
/*
go doc builtin.delete 查看内置函数的用法
func delete(m map[Type]Type1, key Type)
The delete built-in function deletes the element with the specified key
(m[key]) from the map. If m is nil or there is no such element, delete is a
no-op.
*/
}
嵌套map
package main
import "fmt"
func main() {
m1:=make(map[string]string)
m1["name"]="Martin"
m2:=make(map[bool]int)
m2[true]=1
m3:=make(map[[2]int][2]string)
m3[[2]int{1,2}]=[2]string{"a","b"}
m4:=make(map[string]map[string]string)
//{"wife":{"name":"Elizabeth","gender":"Female"} }
m4["wife"]= map[string]string{"name":"Elizabeth","gender":"Female"}
m4["husband"]= map[string]string{"name":"George","gender":"Male"}
m5:=map[string][]int{"n1":[]int{1,3,4},"n2":[]int{2,4,6}}
fmt.Println(m1,m2,m3,m4,m5)
//[{},{},{}]
var a1=make([]map[string]string,1,20)
a1[0]=map[string]string{"name":"eric","gender":"Female","detail":"我是eric我喜欢..."}
a1=append(a1,map[string]string{"name":"egon","gender":"male","detail":"我是egom我喜欢..."})
fmt.Println(len(a1))
fmt.Println(a1)
//map里面嵌套map
v6 := make(map[string]map[int]int)
v6["n1"] = map[int]int{1: 99, 2: 666}
v6["n2"] = map[int]int{2: 33, 4: 444}
fmt.Println(v6)
v7 := make(map[string][2]map[string]string)
v7["group1"] = [2]map[string]string{map[string]string{"name": "Alex", "age": "18"}, map[string]string{"name": "eric", "age": "34"}}
v7["group2"] = [2]map[string]string{map[string]string{"name": "Tony", "age": "28"}, map[string]string{"name": "Bob", "age": "23"}}
fmt.Println(v7)
/*
map[group1:[map[age:18 name:Alex] map[age:34 name:eric]] group2:[map[age:28 name:Tony] map[age:23 name:Bob]]]
{
group1:[
{"name":"Alex","age":"18"},
{"name":"eric","age":"34"}
]
group2:[
{"name":"Tony","age":"28"},
{"name":"Bob","age":"23"}
]
}
*/
}
排序显示map
无论是Python的字典还是Go中的map,它们都是无序的。那么我们如何对map进行排序呢?就需要1些迂回的方法;
对map的key进行排序做成切片,然后遍历切片中的key逐一获取map中的元素。
package main
import (
"fmt"
"math/rand" //math包中有个rand模块
"sort"
"time"
)
func main() {
//获取当前时间的 纳秒(随机数字)
rand.Seed(time.Now().UnixNano())
//声明1个map存放{stud纳秒:分数 }
var scoreMap = make(map[string]int, 200)
for i := 0; i < 100; i++ {
key := fmt.Sprintf("stud%2d", i)
value := rand.Intn(100) //生成0-99的随机整数(作为分数)
scoreMap[key] = value
}
var keys = make([]string, 0, 200)
for key := range scoreMap {
keys = append(keys, key)
}
//安装字符串进行排序
sort.Strings(keys)
//通过排序后的key,对map逐一获取值
for _, key := range keys {
fmt.Println(scoreMap[key])
}
}
切片和map组合数据类型
如何在go里面组织这种多维度的数据类型?
1.make创造1个元素为map的切片
[{"key1":"v1"},{"key2":"v2"}]
创造1个切片[],内部的元素=map[int]string
2.make创造 值(value)为map的切片
{"ke1":["v1","v2","v3"] }
创造 1个map key为 [string] 值为[]string
package main
import (
"fmt"
)
//map和slice组合
func main() {
//1.创造1个切片[],内部的元素=map[int]string
var s1 = make([]map[int]string, 10, 10)
//注意需要对 内部的map也进行初始化
s1[0] = make(map[int]string, 1)
s1[0][10] = "北京"
fmt.Println(s1)
//2.创造1个map
var m2 = make(map[string][]string, 10)
//对map中的切片进行初始化
m2["北京市"] = []string{"朝阳区", "海淀区", "昌平区"}
fmt.Println(m2)
}
总结
目前主要学到了,Go中的数据类型(string、int、bool、pointer、arry、slice、map)以及怎么定义该数据类型的变量,以便于在使用Go的情况下,存放不同数据模型的数据。
ackage main
import "fmt"
func main() {
//声明1个字符串变量
var name string
fmt.Println(name)
//声明1个数组变量
var a1 [3]int
fmt.Println(a1) //声明完了就有默认值
//声明1个切片类型的变量
var s1 []int
fmt.Println(s1 == nil)
//声明二维数组
var a3 [3][3]int
//对二维数组进行初始化
a3 = [3][3]int{
[3]int{1, 2, 3},
[3]int{4, 5, 6},
[3]int{7, 8, 8},
}
fmt.Println(a3)
//
a4 := [3]int{1, 2, 3}
a5 := modifyArry(a4)
fmt.Println(a4)
fmt.Println(a5)
s2 := []string{"北京", "海淀", "五道口"}
s3 := modifySlice(s2)
fmt.Println(s2)
fmt.Println(s3)
//map数据类型
var m1 map[string]int
//注意使用make函数对map进行初始化
m1 = make(map[string]int, 10)
//直接使用map
m2:=make(map[string]int)
m2["name"]=12
fmt.Println(m1,m2)
}
//数组是值类型:修改数组时,会复制 1个新的数组让我们修改
func modifyArry(a1 [3]int) (ret [3]int) {
a1[0] = 100
return a1
}
//切片是引用类型:修改切片时,不会复制1个新的切片让我们修改(修改原来的)
func modifySlice(s2 []string) (ret2 []string) {
s2[0] = "河北省"
return s2
}
练习
//
// //遍历数组
// package main
// import (
// "fmt"
// )
// func main() {
// //根据索引访问元素
// var cities = [...]string{"北京", "上海", "深圳"}
// for i := 0; i < len(cities); i++ {
// fmt.Printf("%s\n", cities[i])
// }
// //遍历数组
// for i, v := range cities {
// fmt.Println(i, v)
// }
// }
// package main
// import (
// "fmt"
// )
// func main() {
// //arry数值类型辩证
// a1 := [...]string{"河北", "河南", "山东"}
// a2 := a1
// a1[len(a1)-1] = "山西"
// fmt.Println(a1) //[河北 河南 山西]
// fmt.Println(a2) //[河北 河南 山东]
// }
//练习题目
// package main
// import (
// "fmt"
// )
// func main() {
// //1.求数组[1, 3, 5, 7, 8]所有元素的和
// arr1 := [...]int{1, 3, 5, 7, 8}
// var sum int
// for _, v := range arr1 {
// sum += v
// }
// fmt.Println(sum)
// /*找出数组中和为指定值的两个元素的下标,比如从数组[1, 3, 5, 7, 8]中找出和为8的两个元素的下标分别为(0,3)和(1,2)*/
// for i := 0; i < len(arr1); i++ {
// for j := i + 1; j < len(arr1); j++ {
// if arr1[i]+arr1[j] == 8 {
// fmt.Printf("%d %d\n", i, j)
// }
// }
// }
// }
// package main
// import "fmt"
// func main() {
// //声明1个字符串变量
// var name string
// fmt.Println(name)
// //声明1个数组变量
// var a1 [3]int
// fmt.Println(a1) //声明完了就有默认值
// //声明1个切片类型的变量
// var s1 []int
// fmt.Println(s1 == nil)
// //声明二维数组
// var a3 [3][3]int
// //对二维数组进行初始化
// a3 = [3][3]int{
// [3]int{1, 2, 3},
// [3]int{4, 5, 6},
// [3]int{7, 8, 8},
// }
// fmt.Println(a3)
// //
// a4 := [3]int{1, 2, 3}
// a5 := modifyArry(a4)
// fmt.Println(a4)
// fmt.Println(a5)
// s2 := []string{"河北", "保定", "唐县"}
// s3 := modifySlice(s2)
// fmt.Println(s2)
// fmt.Println(s3)
// //map数据类型
// var m1 map[string]int
// //注意使用make函数对map进行初始化
// m1 = make(map[string]int, 10)
// //直接使用map
// m2:=make(map[string]int)
// m2["name"]=12
// fmt.Println(m1,m2)
// }
// //数组是值类型:修改数组时,会复制 1个新的数组让我们修改
// func modifyArry(a1 [3]int) (ret [3]int) {
// a1[0] = 100
// return a1
// }
// //切片是引用类型:修改切片时,不会复制1个新的切片让我们修改(修改原来的)
// func modifySlice(s2 []string) (ret2 []string) {
// s2[0] = "河北省"
// return s2
// }
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
var ChineseCount int
s1 := "hello你好少年"
for _, c := range s1 {
//1.判断字符是否为汉字(rune类型)
if unicode.Is(unicode.Han, c) {
ChineseCount++
}
}
fmt.Printf("汉字的数量为:%d\n", ChineseCount)
//2.判断句子中单词出现的次数(word count)
word := "how do you do"
//英文句子中单词以空格隔开
WordArry := strings.Split(word, " ")
wordCountMap := make(map[string]int)
for _, v := range WordArry {
_, ok := wordCountMap[v]
if ok {
wordCountMap[v]++
} else {
wordCountMap[v] = 1
}
}
fmt.Println(wordCountMap)
//3.判断句子是否为以下回文句型
/*
上海自来水来自海上
山西运煤车煤运西山
*/
LoopSting := "山西运煤车煤运西山"
//定义1个存放rune字符串(汉字)的切片
RuneSlice := make([]rune, 0, len(LoopSting))
for _, c := range LoopSting {
RuneSlice = append(RuneSlice, c)
}
for i := 0; i < len(RuneSlice)/2; i++ {
if RuneSlice[i] != RuneSlice[len(RuneSlice)-i-1] {
fmt.Println("不是回文句型")
return //在main函数中 return 程序结束
}
}
fmt.Println("是回文句型")
}