Go语言中的map

Go语言中的map

Go语言中的map是一种内置的数据结构,用于存储键值对(key-value pairs)。map是无序的,并且是可变的。它是实现关联数组、哈希表(hash table)或者字典(dictionary)功能的理想工具。

Go语言中的map由make()函数创建,或者直接通过字面量定义。

map的键和值都可以是任何类型,但键必须是可比较的(支持==和!=运算符的类型)。

使用make()创建map

m := make(map[string]int) // 创建一个键为string类型,值为int类型的map
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
} // 创建并初始化一个map

map的基本操作

m := make(map[string]int)
m["a"] = 1  // 插入一个键值对,"a"键对应的值为1
m["b"] = 2  // 插入另一个键值对,"b"键对应的值为2
m["a"] = 3  // 更新"b"键的值,新的值为3
fmt.Println(m)  // 输出: map[a:3 b:2]

value := m["a"] // 获取键为"a"的值
fmt.Println(value) // 输出: 3

  1. 检查键是否存在

当使用map获取元素时,如果键不存在,返回值的默认值(对于int类型是0)和false。你可以通过第二个返回值检查键是否存在。


value, exists := m["a"]
if exists {
    fmt.Println("Value:", value)
} else {
    fmt.Println("Key does not exist.")
}

value, exists = m["z"]
fmt.Println(exists)  // 输出: false,表示键"z"不存在

  1. 删除元素
delete(m, "a")  // 删除键为"a"的元素
fmt.Println(m)   // 输出: map[b:2]

  1. map的遍历

Go提供了range语句来遍历map,通过range遍历时,你可以获得每个键值对。

m := map[string]int{"a": 1, "b": 2, "c": 3}

for key, value := range m {
    fmt.Println(key, value)
}


a 1
b 2
c 3

注意,map是无序的,因此遍历的顺序每次可能不同。

map的特性

键的类型

Go语言中的map要求键是可比较的类型(即支持==和!=运算符)。

常见的可比较类型包括数字、字符串、指针、接口、数组等。但切片、函数、map本身是不可比较的,因此不能作为map的键。

// 正确
m := make(map[string]int)

// 错误,不能用切片作为键
var m2 map[[]int]int

  1. map的容量和增长

map在内部会根据需要自动扩展容量。

如果map的容量不足,它会自动增加其容量,通常以倍数扩展。

但要注意,map的容量是动态的,并且在插入时没有直接提供容量控制。

可以使用len()函数获取map的元素个数。 fmt.Println(len(m)) // 输出: 2

  1. map是引用类型

map是引用类型,这意味着当你将map赋值给一个新的变量时,两个变量都指向同一块内存区域,修改其中一个会影响另一个。


m1 := map[string]int{"a": 1, "b": 2}
m2 := m1  // m2与m1指向相同的map
m2["a"] = 100
fmt.Println(m1)  // 输出: map[a:100 b:2]
fmt.Println(m2)  // 输出: map[a:100 b:2]

  1. map的性能

map的性能通常是非常高效的,特别是在查找、插入和删除操作上,平均时间复杂度为O(1)(常数时间)。

但是,在极端情况下,map的性能可能会受到哈希冲突的影响,导致性能下降。Go的map会动态调整大小和哈希桶,以尽量减少冲突。

  1. 空map

一个空map可以通过make()函数创建。

注意,未初始化的map(即直接声明而没有通过make()或字面量初始化的map)为nil,对nil的map进行插入会引发运行时错误。

var m map[string]int  // 未初始化的map,默认为nil
fmt.Println(m) // 输出: map[]

m = make(map[string]int) // 正确,创建空map
m["a"] = 1
fmt.Println(m) // 输出: map[a:1]

常见使用场景

map在Go中有许多实际应用场景,包括:

去重:可以使用map来去重,例如从切片中去除重复的元素。

频率统计:通过map统计某个元素出现的次数,常用于文本处理。

缓存/字典:作为简单的缓存或者字典,存储频繁查询的数据。

统计字符频率

str := "hello world"
freq := make(map[rune]int)

// 遍历字符串,统计字符频率
for _, char := range str {
freq[char]++
}

// 打印字符频率表
for key, value := range freq {
fmt.Printf("'%c': %d\n", key, value)
}

去重
func removeDuplicates(nums []int) []int {
        unique := make(map[int]bool) // map的值可以是任意类型,bool类型只用于标记是否存在
        var result []int
        
        for _, num := range nums {
            if _, exists := unique[num]; !exists { // 如果map中没有该元素
            unique[num] = true
            result = append(result, num) // 添加到结果切片
        }
    }
    
    return result
}
func main() {
    nums := []int{1, 2, 3, 2, 4, 1, 5}
    uniqueNums := removeDuplicates(nums)
    fmt.Println(uniqueNums) // 输出: [1 2 3 4 5]
}
使用 map[int]bool 来存储已经出现过的数字,值设为 true,表示该数字已经出现过。

遍历原始切片,若 map 中不存在该元素,则将其加入到结果切片中。

由于 map 中的键是唯一的,重复的数字会被自动忽略。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可能只会写BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值