【go】slice元素去重
在 Go 语言中,slice(切片)本身没有内置的去重方法,但可以通过一些常见的方法手动实现去重。以下是几种常用的去重方式,以及它们的优缺点和适用场景。
一、使用 map 去重(推荐)
利用 map 的键唯一性,可以高效地对 slice 进行去重。这种方法的时间复杂度为 O(n),适用于大多数场景。
示例代码:
package main
import "fmt"
func removeDuplicates(nums []int) []int {seen := make(map[int]bool)result := []int{}for _, num := range nums {if !seen[num] {seen[num] = trueresult = append(result, num)}}return result
}
func main() {nums := []int{1, 2, 2, 3, 4, 4, 5}uniqueNums := removeDuplicates(nums)fmt.Println(uniqueNums) // 输出: [1 2 3 4 5]
}
优点:
- 时间复杂度为 O(n),效率高。
- 适用于任何可比较的类型(如
int
、string
等)。
缺点:
- 需要额外的空间存储 map。
二、使用双重循环去重
如果不希望使用额外的空间,可以通过双重循环的方式去重。这种方法的时间复杂度为 O(n²),适用于小规模数据。
示例代码:
package main
import "fmt"
func removeDuplicates(nums []int) []int {result := []int{}for _, num := range nums {duplicate := falsefor _, v := range result {if num == v {duplicate = truebreak}}if !duplicate {result = append(result, num)}}return result
}
func main() {nums := []int{1, 2, 2, 3, 4, 4, 5}uniqueNums := removeDuplicates(nums)fmt.Println(uniqueNums) // 输出: [1 2 3 4 5]
}
优点:
- 不需要额外的空间存储 map。
- 适用于小规模数据。
缺点:
- 时间复杂度为 O(n²),效率较低,不适合大规模数据。
三、使用 sort.Slice + 遍历去重
如果 slice 是有序的,或者可以接受排序后的结果,可以先对 slice 排序,然后遍历去重。这种方法的时间复杂度为 O(n log n)(排序) + O(n)(遍历) = O(n log n)。
示例代码:
package main
import ("fmt""sort"
)
func removeDuplicates(nums []int) []int {if len(nums) == 0 {return nums}sort.Ints(nums) // 排序result := []int{nums[0]}for i := 1; i < len(nums); i++ {if nums[i] != nums[i-1] {result = append(result, nums[i])}}return result
}
func main() {nums := []int{1, 2, 2, 3, 4, 4, 5}uniqueNums := removeDuplicates(nums)fmt.Println(uniqueNums) // 输出: [1 2 3 4 5]
}
优点:
- 适用于需要排序后去重的场景。
- 时间复杂度比双重循环低。
缺点:
- 会改变原始 slice 的顺序。
- 需要排序操作,可能不适用于所有场景。
四、使用第三方库
如果项目中允许使用第三方库,可以使用一些现成的工具库(如 github.com/samber/lo
)来简化去重操作。
示例代码:
package main
import ("fmt""github.com/samber/lo"
)
func main() {nums := []int{1, 2, 2, 3, 4, 4, 5}uniqueNums := lo.Uniq(nums)fmt.Println(uniqueNums) // 输出: [1 2 3 4 5]
}
优点:
- 代码简洁,适合快速开发。
- 支持多种数据类型和复杂操作。
缺点:
- 需要引入第三方库,可能增加项目依赖。
五、去重方法的对比
方法 | 时间复杂度 | 空间复杂度 | 是否改变顺序 | 适用场景 |
---|---|---|---|---|
map 去重 | O(n) | O(n) | 不改变 | 通用场景,推荐 |
双重循环去重 | O(n²) | O(1) | 不改变 | 小规模数据,无额外空间 |
sort + 遍历去重 | O(n log n) | O(1) | 改变 | 需要排序后去重 |
第三方库(如 lo) | O(n) | O(n) | 不改变 | 快速开发,允许依赖 |
六、总结
- 推荐使用 map 去重:这是最通用且高效的方法,适用于大多数场景。
- 小规模数据:可以使用双重循环去重,避免额外空间开销。
- 需要排序后去重:可以使用
sort.Slice + 遍历
的方式。 - 快速开发:如果允许使用第三方库,可以选择
lo.Uniq
等工具。
根据实际需求选择合适的方法,可以在保证性能的同时简化代码逻辑。