Beaver's Blog

Freedom Openness Inclusion

0%

如何自己在Go中实现set

前言

不像JavaPython等编程语言直接或间接的提供了对set的支持。在Go语言中,内置数据类型并没有提供对集合(set)的支持,但是有相当多的场景下都会用到这种数据类型。这时候,就需要我们自己实现这种类型。

实现

所谓集合,不过是由相同或不同数据类型不同元素所组成的。

对于如何实现set,我们可以考虑根据Go语言已有的数据类型,简单的实现set以满足我们的需要。Go语言内置数据类型中有map数据类型,map的底层是依靠的hash实现的,效率非常高,且map数据类型的key是不会重复的,正好这个特性也能满足set元素不重复的特性。由于map数据类型的形式是map[key_type]value_type,即:map是由key-value组成的,而set只包含元素,没有key-value中的value。但是,我们可以考虑使用Go中空结构体struct{}代替value

我们先声明一个map变量:

1
2
3
var mySet = make(map[int]struct{}, 2)
mySet[1] = struct{}{}
mySet[2] = struct{}{}

上面虽然使用了空结构体struct{}作为set的”value“,但是使用时要写很多的struct{}{},这实在不够简约。现在让我们使用none作为空结构体struct{}的别名。

1
2
3
4
type none struct{}
var mySet = make(map[int]none, 2)
mySet[10] = none{}
mySet[20] = none{}

经过以上步骤,基本实现了set的雏形,我们还要做一些收尾工作:定义一个set类型。

1
type set map[int]none

现在我们就可以使用set了,首先来实现一些set的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var mySet = make(set, N)
// 获取set的元素个数
// 通过内置函数len也可以达到这个目的
func getSetLength(mySet set) int {
return len(mySet)
}
// 判断元素是否在集合中
func elementInSet(mySet set, key key_type) bool {
if _, ok := mySet[key]; ok {
return ok
}
return false
}
// 删除set中元素操作
// 因为定义的set其实根据map实现的,所以对set的操作遵循对map的操作
// 因此,删除set中元素的操作就是执行删除map中元素的操作,使用内置函数delete就可以
delete(mySet, key)
// set新增元素
// 其实,直接执行set[key] = none就能实现set新增元素操作,但还是写一个函数吧。
func add(mySet set, key key_type) set {
mySet[key] = none{}
return mySet
}

上面只是简单实现了一些关于set操作的函数,其实我们可以根据需要实现更多对set的操作。

总结

借助Go中的map,我们算以曲线救国的方式实现了set这个缺失的基础数据类型。虽然Go相比与其他语言足够的简约,设计上的简约可能意味着使用实现上的繁琐,就像set的缺失,其实是让人感觉相当遗憾的事,使得我们想要使用它,就得以自己的方式实现,并需要实现这个类型相关的函数或方法。