前言
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("是回文句型") }