Map遍历 #
一、基本遍历 #
1.1 for-range遍历 #
go
m := map[string]int{"one": 1, "two": 2, "three": 3}
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
1.2 只遍历键 #
go
m := map[string]int{"one": 1, "two": 2, "three": 3}
for key := range m {
fmt.Println(key)
}
1.3 只遍历值 #
go
m := map[string]int{"one": 1, "two": 2, "three": 3}
for _, value := range m {
fmt.Println(value)
}
二、遍历顺序 #
2.1 随机顺序 #
Map遍历顺序是随机的:
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
for i := 0; i < 3; i++ {
fmt.Println("---")
for k, v := range m {
fmt.Println(k, v)
}
}
每次遍历的顺序可能不同。
2.2 为什么随机 #
Go故意随机化遍历顺序,防止程序依赖特定顺序。
三、有序遍历 #
3.1 按键排序 #
go
m := map[string]int{"c": 3, "a": 1, "b": 2}
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s: %d\n", k, m[k])
}
3.2 按值排序 #
go
m := map[string]int{"c": 3, "a": 1, "b": 2}
type pair struct {
key string
value int
}
pairs := make([]pair, 0, len(m))
for k, v := range m {
pairs = append(pairs, pair{k, v})
}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].value < pairs[j].value
})
for _, p := range pairs {
fmt.Printf("%s: %d\n", p.key, p.value)
}
3.3 使用结构体切片 #
go
type Entry struct {
Key string
Value int
}
func sortedByValue(m map[string]int) []Entry {
entries := make([]Entry, 0, len(m))
for k, v := range m {
entries = append(entries, Entry{k, v})
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Value < entries[j].Value
})
return entries
}
四、遍历技巧 #
4.1 遍历时删除 #
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k := range m {
if k == "b" {
delete(m, k)
}
}
fmt.Println(m)
4.2 遍历时修改 #
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
m[k] = v * 2
}
fmt.Println(m)
4.3 遍历时添加 #
遍历时添加新元素可能导致不确定行为:
go
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
m[k+"_new"] = v * 2 // 不推荐
}
4.4 提前退出 #
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
found := false
for k, v := range m {
if v == 2 {
fmt.Println("found:", k)
found = true
break
}
}
五、嵌套Map遍历 #
5.1 二维Map遍历 #
go
m := map[string]map[string]int{
"group1": {"a": 1, "b": 2},
"group2": {"c": 3, "d": 4},
}
for group, subMap := range m {
fmt.Println("Group:", group)
for k, v := range subMap {
fmt.Printf(" %s: %d\n", k, v)
}
}
5.2 安全遍历嵌套Map #
go
for group, subMap := range m {
if subMap == nil {
continue
}
for k, v := range subMap {
fmt.Printf("%s.%s: %d\n", group, k, v)
}
}
六、遍历性能 #
6.1 预分配切片 #
go
keys := make([]string, 0, len(m)) // 预分配容量
for k := range m {
keys = append(keys, k)
}
6.2 避免重复访问 #
go
// 不好:重复访问
for _, k := range keys {
v := m[k]
process(k, v)
v2 := m[k] // 重复访问
process2(k, v2)
}
// 好:缓存值
for _, k := range keys {
v := m[k]
process(k, v)
process2(k, v)
}
七、实际应用 #
7.1 统计并排序 #
go
func topN(m map[string]int, n int) []string {
type pair struct {
key string
value int
}
pairs := make([]pair, 0, len(m))
for k, v := range m {
pairs = append(pairs, pair{k, v})
}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].value > pairs[j].value
})
result := make([]string, 0, n)
for i := 0; i < n && i < len(pairs); i++ {
result = append(result, pairs[i].key)
}
return result
}
7.2 分组统计 #
go
func groupCount(items []Item) map[string]int {
groups := make(map[string]int)
for _, item := range items {
groups[item.Category]++
}
return groups
}
7.3 转换为切片 #
go
func mapToSlice(m map[string]int) []Entry {
result := make([]Entry, 0, len(m))
for k, v := range m {
result = append(result, Entry{Key: k, Value: v})
}
return result
}
八、总结 #
Map遍历要点:
| 遍历方式 | 说明 |
|---|---|
| for k, v := range m | 遍历键值对 |
| for k := range m | 只遍历键 |
| for _, v := range m | 只遍历值 |
关键点:
- 随机顺序:Map遍历顺序不确定
- 有序遍历:需要先提取键并排序
- 遍历修改:可以修改值,但添加新键要小心
- 性能优化:预分配切片容量
- 嵌套遍历:注意检查nil
准备好学习Map实战了吗?让我们进入下一章!
最后更新:2026-03-26