Map数据结构
哈希表是一个无序的key/value的集合,其中所有key都不相同,通过给定的key可以在常数时间复杂度内检索、更新或删除对用的value。
map的声明
1、创建map
// 内置make函数
ages := make(map[string]int) // mapping from strings to ints
ages["zhangsan"] = 31
ages["lisi"] = 34
// 或者使用字面值语法
ages := map[string]int{
"zhangsan": 31,
"lisi": 34,
}
// 创建空的map
ages := map[string]int{}
// x += y 和 x++ 等简短赋值语法也可以用在map
ages["zhangsan"] += 1
ages["zhangsan"] ++
// map中的元素并不是一个变量,不能对map的元素进行取址操作
_ = &ages["zhangsan"] // compile error
2、删除map元素
// 删除操作是安全的,元素不存在,返回value类型对应的零值
delete(ages, "zhangsan")
3、遍历map
使用range风格的for循环实现,和之前的slice遍历语法类似。map的迭代顺序是不确定的,不同的哈希函数实现可能导致不同的遍历顺序。这是有意为之,每次都使用随机的遍历顺序可以强制要求程序不会依赖具体的哈希函数实现。
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, age)
}
// 按顺序遍历key/value对,显式地对key进行排序,使用sort包的Strings函数对字符串slice进行排序
import "sort"
var names []string
for name := range ages {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
fmt.Printf("%s\t%d\n", name, ages[name])
}
// 如果一开始就知道names的最终大小,给slice分配一个合适的大小将会更有效。lice的容量刚好可以放下map中全部的key
names := make([]string, 0, len(ages))
4、零值
map类型的零值是nil,即没有引用任何哈希表。
var ages map[string]int
fmt.Pringln(ages == nil) // "true"
fmt.Pringln(len(ages) == 0) // "true"
在向map存数据前必须先创建map。通过key作为索引下标来访问map将产生一个value。如果key存在将得到与key对应的value;如果key不存在,那么将得到value对应类型的零值。
age, ok := ages["wangwu"]
if !ok {/*"wangwu" is not a key in this map; age == 0 */}
if age, ok := ages["wangwu"]; !ok { /* */ }
和slice一样,map之间不能进行相等比较;唯一的例外是和nil进行比较。要判断两个map是
否包含相同的key和value,我们必须通过一个循环实现:
func equal(x, y map[string]int) bool {
if (len(x) != len(y)) {
return false
}
for k, xv := range x {
if yv, ok := y[k]; !ok || yv != xv {
return false
}
}
return true
}
// 上面方法中我们不能简单地用xv!=y[k]判断,因为会导致在判断下面两个map时产生错误的结果:
equal(map[string]int{"A": 0}, map[string]int{"B": 42}) // return true