二维数组概念:一维数组中的元素又是一个一维数组。
var arr [4][6]int // [ [0 0 0 0 0 0] [0 0 0 0 0 0] [0 0 0 0 0 0] [0 0 0 0 0 0] ]
arr [1][2] = 1
arr [2][3] = 2
arr [3][4] = 3
fmt.Println(arr) // [[0 0 0 0 0 0] [0 0 1 0 0 0] [0 0 0 2 0 0] [0 0 0 0 3 0]]
二维数组内存分析:
[4][6]这个矩阵一共24个int元素,每个int元素在x64计算机内占8bytes,所以这个二维数组占据24*8也就是192Bytes的空间。
由于4个6元素数组构成矩阵,每6个元素为一个数组的首地址一定和a[i]的内存地址是一样的,即为 &a[i] == &a[i][0]。
二维数组遍历
package main
import "fmt"
func main() {
/*
示例,初始化一个二维数组
*/
//写法可以省略,var arr [2][3]int = [2][3]int{{1,2,3},{4,5,6}}
var arr = [2][3]int{{1,2,3},{4,5,6}}
fmt.Println(arr)
//传统遍历
for i:=0 ; i < len(arr) ; i++ { //替换为len(arr)
for j := 0 ; j < len(arr[i]) ; j++ { //替换为len(arr[i])
fmt.Printf("%d ",arr[i][j])
}
fmt.Println()
}
// for-range 遍历
for i ,value1 := range arr {
for j , value2 := range value1 {
fmt.Printf("a[%v][%v] = %v\n",i,j,value2)
}
}
}
map的声明
声明:
var
key:多种类型,布尔,int,float,string,ptr,channel,一般用的最多的是int和string,其他用法很奇怪。
slice,func,map是不可以作为key的,因为无法使用 "=="来判断。
values: 可以是int,string,float,struct,map(见例3)
★★★与数组类型不一样,map的声明是不会分配内存的,初始化需要make(),分配内存后才能赋值和使用,不是默认值为0,"",false等,map与数组不同,是无序的。
类似python中的字典,字典嵌套字典,且无序
示例1:
package main
import "fmt"
func main() {
var testmap map[string]string
fmt.Println(testmap)
} //map[] 这个是反馈结果
示例2:
package main
import "fmt"
func main() {
var testmap map[string]string
testmap["name"] = "durant"
fmt.Println(testmap)
} //panic: assignment to entry in nil map 因为没有分配内存
示例3:
package main
import "fmt"
func main() {
var testmap map[string]string
testmap = make(map[string]string,10)
testmap["name"] = "durant"
fmt.Println(testmap)
} //使用make函数分配一个10对kv的map,10这里不传参数默认为1,注意写法 返回结果map[name:durant]
示例4:
package main
import "fmt"
func main() {
var testmap map[string]string
testmap = make(map[string]string,10)
testmap["name"] = "durant"
testmap["name"] = "james"
testmap["name1"] = "james"
fmt.Println(testmap)
} //一个map中key只能唯一,后面你会覆盖前面的;不同的key可以有同一个值 返回结果为map[name:james name1:james]
map的使用方式:
1. 按照上述使用make()对map进行声明,然后赋值:
var testmap map[string]string
testmap = make(map[string]string,10)
testmap[“key”] = “values”
2. 直接简化上述,直接声明,然后赋值:
var testmap = make(map[string]string,10)
testmap[“key”] = “values”
3. 简化上述两版,不使用make(),直接声明后赋值:
var testmap = map[string]string{“key”:“values”,“key1”:“values1”}
testmap[“key2”] = “values2”
案例:三个球员编号为001,002,003,每个编号可以查询他们的姓名和球衣号码,每个学生名字为 durant james curry,球衣号码35,23,30
下面为简略写法,大同小异,取值都是通过 [key] —> [key][key] 这种方式取值。
package main
import "fmt"
func main() {
var nba = map[string]map[string]string{"001":{"name":"durant","num":"35"}}
fmt.Println(nba) //map[001:map[name:durant num:35]]
fmt.Println(nba["001"]) //map[name:durant num:35]
fmt.Println(nba["001"]["name"]) //durant
}
map的CRUD
1. map的增加和更新: map[key] = value ,如果key不存在就增加©,如果key存在就是修改(U)。
见下面示例
package main
import "fmt"
func main() {
var nba = map[string]map[string]string{"001":{"name":"durant","num":"35"}}
nba["001"]["name"] = "james"
nba["002"] = make(map[string]string,2) //分配新的内存空间给map中key对应的值map
nba["002"]["name"] = "durant"
nba["002"]["num"] = "35"
fmt.Println(nba) //map[001:map[name:durant num:35]]
fmt.Println(nba["001"]) //map[name:durant num:35]
fmt.Println(nba["001"]["name"]) //james
fmt.Println(nba["002"]["name"]) //durant
}
2. map的删除:使用delete(),使用方式为 delete(
package main
import "fmt"
func main() {
var nba = map[string]map[string]string{"001":{"name":"durant","num":"35"}}
nba["001"]["name"] = "james"
nba["002"] = make(map[string]string,2)
nba["002"]["name"] = "durant"
nba["002"]["num"] = "35"
delete(nba["001"],"name") //删除二层key
delete(nba,"002") //删除一层key
delete(nba,"003") //不存在003的,不会报错,什么也不操作
fmt.Println(nba) //map[001:map[num:35]]
fmt.Println(nba["001"]) //map[num:35]
fmt.Println(nba["001"]["name"]) //不存在
fmt.Println(nba["002"]["name"]) //不存在
nba = make(map[string]map[string]string)
fmt.Println(nba) //删除其中所有的key太麻烦,直接指向空map
}
细节:golang中没有删除所有key的函数,只能使用遍历,然后for删除;让map指向一个新的make(),让原来的成为垃圾,被gc回收。
3. map的查找:
package main
import "fmt"
func main() {
var testmap map[string]string
testmap = make(map[string]string,10)
testmap["name"] = "james"
fmt.Println(testmap)
dest_key , value := testmap["shit"] //如果要找一个key是否存在,可以使用if { "打印出对应的key",key}
if value {
fmt.Println("这个key存在")
} else {
fmt.Println("没找到这个key")
}
map的遍历:
由于map的数据类型复杂,所以不能使用单纯for进行遍历,只能使用for-range
这个完全类似python的字典遍历,for k,v in xxx.items(): …
一层map:
package main
import "fmt"
func main() {
var testmap = map[string]string{"name1":"durant","name2":"james"}
for k,v := range testmap{
fmt.Printf("%v %v\n",k,v)
}
}
//对比下python的字典
dict = {"name1":"durant","name2":"james"}
for k,v in dirt.items()
print("%s %s\n",k,v)
二层map,也就是一层map的值是map,<一层map>[
package main
import "fmt"
func main() {
var testmap = map[string]map[string]string{"thunder":{"name1":"durant"},"lackers":{"name2":"james"}}
for k1,v1 := range testmap { //先把一层的k,v拿出来,"二层的map" == "一层的v"
fmt.Printf("%v %v\n",k1,v1) //thunder map[name1:durant];lakers map[name2:james]
for k2,v2 := range v1 { //内层循环要拿v1这个map的值,里面再对应k2,v2
fmt.Printf("%v %v\n",k2,v2) //name1 durant;name2 james 其实就是注意层级关系
}
}
//map的长度统计:
len() 得到的结果是里面包含多少个kv对。
fmt.Println(len(testmap)) //2个kv对 雷霆和湖人
fmt.Println(len(testmap["thunder"])) //1个kv对 球员姓名
}
map的切片与添加元素
使用map切片,这样使用则map个数可以动态变化,不用再考虑kv对限制了。
案例演示:使用map记录NBA球员的姓名和年龄,要求可以根据需求动态增加球员信息,球员数不定。
package main
import "fmt"
func main() {
/*
使用map记录不同球队的NBA球员的姓名和年龄,要求可以根据需求动态增加球员信息,球员数不定。
*/
var nbaPlayer []map[string]string
nbaPlayer = make([]map[string]string,2) //切片类型首先要用make分配内存
if nbaPlayer[0] == nil {
nbaPlayer[0] = make(map[string]string,2) //继续为map类型分配内存,所以一共需要分配两次内存
nbaPlayer[0]["name"] = "durant"
nbaPlayer[0]["age"] = "30"
}
if nbaPlayer[1] == nil {
nbaPlayer[1] = make(map[string]string,2) //继续为map类型分配内存,所以一共需要分配两次内存
nbaPlayer[1]["name"] = "james"
nbaPlayer[1]["age"] = "35"
}
//由于上限设置为2,所以kv对只能有两个,如果现在写nbaPlayer[2]一定会报错out of range
//所以使用append()动态添加,先定义一个新的player,然后添加到前面就可以了
add_nbaPlayer := map[string]string{"name":"curry","age":"29"} //添加一个新球员,用另外一个map
nbaPlayer = append(nbaPlayer,add_nbaPlayer) //append()需要赋值给原切片
/*
追加结果[map[age:30 name:durant] map[age:35 name:james] map[age:29 name:curry]]
*/
fmt.Println(nbaPlayer)
}
map的排序
package main
import (
"fmt"
"sort"
)
func main() {
/*
1. map本身作为字典就是无序的。
2. golang中没有针对map排序的方法。
3. 想排序先对map中的key进行排序,然后根据key值遍历输出即可。
4. 排序方法:map中所有的key放入切片中,对切片进行排序,遍历切片,按照key来输出map的值
*/
var nbaPlayers = map[int]string{30:"curry",23:"james",35:"durant",1:"mcgrady"}
fmt.Println(nbaPlayers)
//这样每次输出都是无序的,把所有的key添加到一个切片中
var slice_key []int
//使用for-range方式遍历map,取出keys和values
for keys, _ := range nbaPlayers {
slice_key = append(slice_key,keys)
}
//使用sort.Ints([]int)方法,对int型切片进行递增排列
sort.Ints(slice_key) //这个方法解决了冒泡的问题,如果从大到小排列则只需用转置方法来解决
fmt.Println(slice_key)
//这时key已经成功取出成为切片,那么接下来要遍历切片,取出所有的value值作为map nbaPlayer的key
for _ , v := range slice_key{
fmt.Println(nbaPlayers[v])
}
}
map使用细节
引用类型数据,函数接收map修改后,调用后会直接改变原map值。
package main
import "fmt"
func modify(test map[int]int) {
test[2] = 6 //下标为2的数值改为6
}
func main() {
var test map[int]int
test = make(map[int]int,3)
test[0] = 3
test[1] = 4
test[2] = 5
modify(test)
fmt.Println(test) //map[0:3 1:4 2:6] 不再是5,直接改成6了
}
map的容量会自动扩容,不会发生panic。
map的value也经常使用结构体struct,比map更好,结构体里面可以包含不同的数据类型。
示例1:
package main
import "fmt"
func modifyUser(users map[string]map[string]string, name string,nickName string) {
if users[name] != nil {
users[name]["pwd"] = "888888"
} else {
users[name] = make(map[string]string,2) //嵌套map需要make()两次,外层内层都需要make()
users[name]["nickName"] = nickName
users[name]["pwd"] = "111111"
}
}
func main() {
/*
需求:某个用户名存在,将其密码修改为"888888";
不存在则创建用户,包含信息nickName和pwd
*/
var users map[string]map[string]string
users = make(map[string]map[string]string,2)
modifyUser(users,"Jimmy","jim")
fmt.Println(users)
modifyUser(users,"Jimmy","jim")
fmt.Println(users)
}