Go 语言判断元素列表里是否包含某个元素,通常有两种方法:遍历列表、转为map后判断是否包含key。
遍历列表
对 []string
遍历判断
1
2
3
4
5
6
7
8
9
func ContainsStr(slice []string, element string) bool {
for _, e := range slice {
if e == element {
return true
}
}
return false
}
对 []int
遍历判断
1
2
3
4
5
6
7
8
9
func ContainsInt(slice []int, element int) bool {
for _, e := range slice {
if e == element {
return true
}
}
return false
}
如果 slice
是其它类型呢?是不是要挨个写判断函数。
go 1.18+ 有个 comparable
类型,定义的可比较类型:
- Boolean values
- Integer values
- Floating point values
- Complex values
- String values
- Pointer values
- Channel values
- Interface values
- Struct values are comparable if all their fields are comparable
- Array values are comparable if values of the array element type are comparable
- A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T
就可以写成如下通用函数:
1
2
3
4
5
6
7
8
9
func ContainsGeneric[T comparable](slice []T, element T) bool {
for _, e := range slice {
if e == element {
return true
}
}
return false
}
使用也很简单
1
2
3
4
5
6
var stringSlice = []string{"item 1", "item 2"}
var intSlice = []int{1, 2, 3}
fmt.Println(Contains(stringSlice, "item 2")) // true
fmt.Println(Contains(intSlice, 4)) // false
转换成 map 判断
把 slice 元素的值作为 map 的 key,如:
1
2
3
4
5
sliceLen := 100
mapInt := map[int]struct{}{}
for i := 0; i < sliceLen; i++ {
mapInt[i] = struct{}{}
}
判断是否存在,为了与上面函数风格相同就这么写
1
2
3
4
func ContainsMapStr(mp map[string]struct{}, element string) bool {
_, ok := mp[element]
return ok
}
性能比较
测试 30 个元素结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sliceLen: 30
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
BenchmarkContainsGenericStr
BenchmarkContainsGenericStr-8 872523 1346 ns/op 0 B/op 0 allocs/op
BenchmarkContainsGenericInt
BenchmarkContainsGenericInt-8 5177288 227.3 ns/op 0 B/op 0 allocs/op
BenchmarkContainsStr
BenchmarkContainsStr-8 862272 1353 ns/op 0 B/op 0 allocs/op
BenchmarkContainsInt
BenchmarkContainsInt-8 4781001 256.3 ns/op 0 B/op 0 allocs/op
BenchmarkContainsMapStr
BenchmarkContainsMapStr-8 1623274 741.8 ns/op 0 B/op 0 allocs/op
BenchmarkContainsMapInt
BenchmarkContainsMapInt-8 1863303 626.6 ns/op 0 B/op 0 allocs/op
测试 100 个元素结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sliceLen: 100
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
BenchmarkContainsGenericStr
BenchmarkContainsGenericStr-8 66457 18719 ns/op 0 B/op 0 allocs/op
BenchmarkContainsGenericInt
BenchmarkContainsGenericInt-8 533656 2182 ns/op 0 B/op 0 allocs/op
BenchmarkContainsStr
BenchmarkContainsStr-8 66378 17976 ns/op 0 B/op 0 allocs/op
BenchmarkContainsInt
BenchmarkContainsInt-8 560392 2133 ns/op 0 B/op 0 allocs/op
BenchmarkContainsMapStr
BenchmarkContainsMapStr-8 454953 2694 ns/op 0 B/op 0 allocs/op
BenchmarkContainsMapInt
BenchmarkContainsMapInt-8 607315 1956 ns/op 0 B/op 0 allocs/op
性能小结
- 使用遍历
slice
判断的方式,slice 元素是comparable
或具体的string
或int
,性能差不多;int
类型比string
类型要快 6 倍左右。 - 使用
map
查询时,key 的类型int
比string
稍快一点,相差不大。 slice
与map
性能跟元素个数有关系,可以参见以前的一个测试 Golang slice 和 map 的查询性能比较
优化方案,首先看元素个数,其次看元素类型(这里指常见的 int/string)。
- 15 个以下,无论是 int 还是 string,建议用
slice
- 15 ~ 100 个,尽量转为 int ,如果不能转为 int 就用 map
- 100 个以上,果断用 map,int 和 string 都差不多
本文网址: https://golangnote.com/topic/309.html 转摘请注明来源