巧用 Go Map 特性对数组或切片去重

举报
陈明勇0423 发表于 2023/04/30 19:34:19 2023/04/30
【摘要】 本文介绍了如何利用 Go 的复合数据类型 Map 的特性对数组或切片进行去重。值得注意的一个地方是,在使用 Map 构建 Set 时,Value 的数据类型指定为 struct{},原因是后面在添加键值对的时候,指定的 Value 为空结构体 strcut{}{},空结构体不占用内存空间。

作者:陈明勇
专注分享后端知识,如果文章对您有帮助,欢迎点赞收藏加关注,一起学习,一起进步!

前言

在其他语言里(如 Java )使用过 Set 集合的小伙伴都知道,它的一个特点就是集合里的元素是不重复的。在一些需要去重场景中,我们可以使用 Set 这种数据结构去存储数据,达到去重的目的。而在 Go 语言里面,是没有 Set 这种数据类型的。如果我们想利用无重复元素的数据结构对数组或切片去重,可以使用 Go 的复合数据类型 Map 去构建 Set 集合,对数组或切片进行去重。因为 Map 中的 key 是唯一的,如果不了解 Map 的小伙伴,可以看看我的这篇文章 一文了解 Go 的复合数据类型(数组、Slice 切片、Map)
。

使用 Map 构建 Set

type MySet map[any]struct{}

定义一个自定义类型 MySet ,具有 map[any]strcut{} 的特性。

  • map 的 key 是 any 类型,任何类型都可以当做 map 的 key;
  • map 的 value 是 struct{} 类型,为什么会用结构体类型?是因为后面添加 k-v 键值对时,指定的 value 为 空结构体 strcut{}{},fmt.Println(unsafe.Sizeof(struct{}{})) // 0 空结构体是不占用内存空间的。

对数组或切片去重

import "fmt"

type MySet map[any]struct{}

func main() {
	s1 := []int{1, 1, 2, 3}
	fmt.Println(duplicateRemoving(s1)) // [1 2 3]
	s2 := []string{"a", "b", "c", "a"}
	fmt.Println(duplicateRemoving(s2)) // [a b c]
}

func duplicateRemoving[T any](s []T) []T {
	res := make([]T, 0, len(s))
	mySet := make(MySet)
	for _, t := range s {
		if _, ok := mySet[t]; !ok {
			res = append(res, t)
			mySet[t] = struct{}{}
		}
	}
	return res
}

核心思路

  • 定义一个新的切片 res,为去重后的切片;定义一个 MySet 类型的变量 mySet,用于判断元素是否重复;
  • 遍历原切片 s,首先判断 mySet 里是否存在以切片 s 的元素 t 为 key 的键值对,如果不存在,往新切片 res 添加元素 t,往 mySet 里添加键值对 t → struct{}{},否则说明元素重复,不做添加操作;
  • 返回去重后的新切片。

小结

本文介绍了如何利用 Go 的复合数据类型 Map 的特性对数组或切片进行去重。值得注意的一个地方是,在使用 Map 构建 Set 时,Value 的数据类型指定为 struct{},原因是后面在添加键值对的时候,指定的 Value 为空结构体 strcut{}{},空结构体不占用内存空间。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。