Go語言學習13-map
0x00 定義
對映(map),Go語言中內建的一種型別,它將鍵值對相關聯,我們可以通過鍵key來獲取對應的值value。類似其他語言的集合。
map是一種無序的基於key-value
的資料結構,Go語言中的map是引用型別,必須初始化才能使用。
鍵值對:一對匹配的資訊
Go語言中 map
的定義語法如下:
map[KeyType]ValueType
其中,
- KeyType:表示鍵的型別。
- ValueType:表示鍵對應的值的型別。
map型別的變數預設初始值為nil,需要使用make()函式來分配記憶體。語法為:
make(map[KeyType]ValueType, [cap])
其中cap表示map的容量,該引數雖然不是必須的,但是我們應該在初始化map的時候就為其指定一個合適的容量。
PS:key、value型別:bool、數字、string、指標、channel、還可以是隻包含前面幾個型別的介面、結構體、陣列
PS:key通常為int、string型別、value通常為數字(整數、浮點數)、string、map、結構體
PS:slice、map、function不可
0x01 map基本使用
map中的資料都是成對出現的,map的基本使用示例程式碼如下:
func main() { scoreMap := make(map[string]int, 8) //一次性定義好容量,有利於程式的快捷 scoreMap["張三"] = 90 scoreMap["小明"] = 100 fmt.Println(scoreMap) fmt.Println(scoreMap["小明"]) fmt.Printf("type of a:%T\n", scoreMap) }
輸出:
map[小明:100 張三:90]
100
type of a:map[string]int
map也支援在宣告的時候填充元素,例如:
func main() {
userInfo := map[string]string{
"username": "沙河小王子",
"password": "123456",
}
fmt.Println(userInfo) //
}
0x02 判斷某個鍵是否存在
Go語言中有個判斷map中鍵是否存在的特殊寫法,格式如下:
value, ok := map[key]
舉個例子:
func main() { var m1 map[string]int //這是map初始化 //fmt.Println(m1 == nil) 返回的是一個true,說明此為空,還未初始化,在記憶體中沒有開闢空間 m1 = make(map[string]int, 10) //可以自動擴容,但是初始化的時候最好估算好該map的容量,避免在程式執行期間再動態擴容 //10就是鍵值對的數量 m1["beijing"] = 1 m1["shanghai"] = 2 m1["jiwuming"] = 35 fmt.Println(m1) fmt.Println(m1["beijing"]) value, ok := m1["nihao"] //約定成俗,用ok接收別的返回的bool值!如果key存在ok為true,v為對應的值;不存在ok為false,v為值型別的零值 if !ok { fmt.Println("查無此人!") } else { fmt.Println(value) } }
0x03 map的遍歷
Go語言中使用for range
遍歷map。
func main() {
scoreMap := make(map[string]int)
scoreMap["張三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k, v := range scoreMap {
fmt.Println(k, v)
}
}
但我們只想遍歷key的時候,可以按下面的寫法:
func main() {
scoreMap := make(map[string]int)
scoreMap["張三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k := range scoreMap {
fmt.Println(k)
}
}
注意: 遍歷map時的元素順序與新增鍵值對的順序無關。
0x03 特點
1、map集合在使用前一定要make
2、map的key-value是無序的
3、key是不可以重複的,如果遇到重複,後一個value會覆蓋之前的
4、value是可以重複的
【4】三種map建立方式
方式一:var然後make函式(不推薦,瞭解)
var a map[int]string
//只宣告map,記憶體是沒有分配空間的
//必須通過make函式進行初始化才能分配空間
a = make(map[int]string, 10) //map可以存放10個鍵值對
a[2000] = "張三"
a[2001] = "李四"
方式二:推斷
b := make(map[int]string)
b[1] = "beijing"
b[2] = "shanghai"
b[3] = "guagndong"
方式三:類似json格式的
c := map[int]string{
1 : "beijing",
2 : "shanghai",
3 : "guangdong", //一定要注意逗號,千萬不能忘掉
}
【5】map的增刪改
增加與修改
使用delete()函式刪除鍵值對
使用delete()
內建函式從map中刪除一組鍵值對,delete()
函式的格式如下:
delete(map, key)
其中,
- map:表示要刪除鍵值對的map
- key:表示要刪除的鍵值對的鍵
示例程式碼如下:
func main(){
scoreMap := make(map[string]int)
scoreMap["張三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
delete(scoreMap, "小明")//將小明:100從map中刪除
for k,v := range scoreMap{
fmt.Println(k, v)
}
}
delete(b, 2)
delete(b, 5)
fmt.Println(b)
注意:清空操作
1、刪除map中的所有key,沒有一個專門的方法一次性刪除,可以遍歷一下key,逐個刪除;或者手動一個一個刪除
2、不過上面這個方法過於麻煩,所以我們怎麼做呢,就是通過map = make(...),make一個新的,讓原來的成為垃圾,被gc回收
查詢
value, flag := b[4]
fmt.Println(value, flag)
按照指定順序遍歷map
package main
import (
"fmt"
"math/rand"
"sort"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())//當前時間的納秒輸出,並且隨機化
scoreMap := make(map[string]int) //新建一個map
for i := 0; i < 100; i++ {
key := fmt.Sprintf("Stu%02d", i) //for迴圈輸出99個學生名稱,並賦予給key變數
value := rand.Intn(100) //隨機生成1-100賦值給value變數
scoreMap[key] = value //將scoreMap的key和value一一對應起來
}
// fmt.Println(scoreMap)
//將結果列印到切片中
var keys = make([]string, 0, 200)
for key := range scoreMap {
keys = append(keys, key)
}
//隨後對切片進行排序
sort.Strings(keys)
//按照排序後的keys進行遍歷
for _, key := range keys {
fmt.Println(key, scoreMap[key])
}
}
map與slice結合
map和slice都要初始化
下面這段程式碼,可以看到,make函式製作了一個切片,這個切片是map[int]string型別的。下方這個panic錯誤是因為make了一個切片,沒有任何的數值,所以我們需要新建一個數值,來保證不會顯示索引越界錯誤。
func main() {
m1 := make([]map[int]string, 0, 10)
m1[0][100] = "beijing"
fmt.Println(m1)
}
當我將make函式裡面的長度變成1,就會顯示nil,為空,是因為map並沒有初始化,也就是賦值之類的。所以需要對map進行初始化。
func main() {
m1 := make([]map[int]string, 0, 10)
m1[0][100] = "beijing"
fmt.Println(m1)
}
對map進行初始化
func main() {
m1 := make([]map[int]string, 10, 10)
m1[0] = make(map[int]string, 1) //m1第一個map進行初始化
m1[0][10] = "beijing" //m1第一個map的值賦值,因為一共有10個map,剩餘9個就預設是空值
fmt.Println(m1)
}
元素為map型別的切片
下面的程式碼演示了切片中的元素為map型別時的操作:
func main() {
var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println("after init")
// 對切片中的map元素進行初始化
mapSlice[0] = make(map[string]string, 10)
mapSlice[0]["name"] = "小王子"
mapSlice[0]["password"] = "123456"
mapSlice[0]["address"] = "沙河"
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
}
值為切片型別的map
啥意思?就是平時我們新建map的時候,是make(map[int]string)
,這回把string
替換成[]string
切片型別。
m2 := make(map[string][]string, 10)
m2["beijing"] = []string{"朝陽區", "海淀區", "東城區", "房山區", "昌平區"}
m2["shanghai"] = []string{"上海外灘", "莆田區", "老八區"}
fmt.Println(m2)
總結
舉上面這兩個例子的目的是為了提醒,map和切片在定義後,一定要初始化!
練習題
-
寫一個程式,統計一個字串中每個單詞出現的次數。比如:”how do you do”中how=1 do=2 you=1。
思路總結一下:
- 先字串切割成切片,然後遍歷這些切片到map
- 再判斷每個單詞是否在map中
- 累計一下每個單詞出現的次數
-
觀察下面程式碼,寫出最終的列印結果。
func main() {
type Map map[string][]int //定義Map的型別為 map[string][]int,也就是值為切片的map型別
m := make(Map) //初始化一個Map,賦予變數給m
s := []int{1, 2} //s定義為一個具有兩個值的切片
s = append(s, 3) //新增一個數值,即s = []int{1,2,3}
fmt.Printf("%+v\n", s) //列印s
m["q1mi"] = s //m的qlmi鍵對應值為s
s = append(s[:1], s[2:]...) //刪除s[1]=2
fmt.Printf("%+v\n", s) //s={1,3}
fmt.Printf("%+v\n", m["q1mi"]) //m["qlmi"]=[]int{1,2,3}
}