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

举报
陈明勇0423 发表于 2023/04/30 19:34:19 2023/04/30
918 0 0
【摘要】 本文介绍了如何利用 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{} 的特性。

  • mapkeyany 类型,任何类型都可以当做 mapkey
  • mapvaluestruct{} 类型,为什么会用结构体类型?是因为后面添加 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 的元素 tkey 的键值对,如果不存在,往新切片 res 添加元素 t,往 mySet 里添加键值对 t → struct{}{},否则说明元素重复,不做添加操作;
  • 返回去重后的新切片。

小结

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

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

作者其他文章

评论(0

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

    全部回复

    上滑加载中

    设置昵称

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

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

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