用map去重最快(O(n))但不保序;需保序则一次遍历+seen判断即可;小数据量(如n≤30)可用双重循环,O(n²)但无额外内存开销。

用 map 去重最常用,但顺序不保
Go 没有内置 Set,所以靠 map 的键唯一性模拟是最自然的选择。它快(O(n)),写起来也干净,适合绝大多数场景。
- 对
[]string、[]int等可比较类型直接可用 - 去重后元素顺序是随机的——因为
map遍历无序,for k := range m不保证和原 slice 一致 - 如果业务依赖原始顺序(比如日志行、配置项列表),不能直接用这个方法
- 注意:
map[string]bool和map[string]struct{}都可以,后者更省内存(struct{}占 0 字节),但可读性略低
示例关键逻辑:
seen := make(map[int]bool)
result := make([]int, 0)
for _, v := range nums {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
要保留原始顺序?得加个 seen 判断 + 单次遍历
很多人卡在这儿:想用 map 的高效,又不想丢顺序。其实不用额外排序或两遍循环,一次遍历就能搞定。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 核心是「只在第一次见到时才追加」,而不是先塞满
map再倒腾出来 - 避免了无序遍历
map这一步,天然保持输入顺序 - 空间开销和纯
map法一样,时间也是O(n) - 别手滑写成
if seen[v] == false——初始零值就是false,但未初始化的 key 访问会自动补零,所以直接!seen[v]更安全
小数据量或内存敏感?考虑双重循环
当 slice 长度稳定在几十以内,或者你明确不想多占一块 map 内存(比如嵌入式或极低配环境),双重循环反而更直白、无隐式分配。
立即学习“go语言免费学习笔记(深入)”;
- 时间复杂度是
O(n²),但n=30时也就 900 次比较,实际感知不到慢 - 不依赖任何额外数据结构,适合写进 tight loop 或 hot path 中
- 注意内层循环别越界:
for j := range result是安全的,但手动写j 要小心并发修改 - 别用它处理几百以上的元素——CPU 时间会明显跳升
别踩这些坑:类型、指针、结构体
map 去重看似万能,但一碰到不可比较类型就直接报错。
-
[]int、map[string]int、func()、含切片字段的 struct —— 全部不能做map键,编译失败 - 想对
[]*MyStruct去重?可以,但比的是指针地址,不是结构体内容;若想按字段去重,得自己实现哈希或用reflect.DeepEqual(性能差) - 字符串去重要注意 Unicode:`"é"` 和 `"e\u0301"` 在 Go 里是两个不同字符串,
map不会合并它们 - 别在循环里反复
make(map[T]bool)又扔掉——高频调用时建议复用map实例或用 sync.Pool

















