Go 语言判断元素列表里是否包含某个元素,通常有两种方法:遍历列表、转为map后判断是否包含key。

遍历列表
对 []string
遍历判断
Go: range string slice
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
遍历判断
Go: range int slice
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
就可以写成如下通用函数:
Go: ContainsGeneric
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
}
|
使用也很简单
Go: ContainsGeneric 使用
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,如:
Go: slice to map
1
2
3
4
5 |
sliceLen := 100
mapInt := map[int]struct{}{}
for i := 0; i < sliceLen; i++ {
mapInt[i] = struct{}{}
}
|
判断是否存在,为了与上面函数风格相同就这么写
Go: map ok
1
2
3
4 |
func ContainsMapStr(mp map[string]struct{}, element string) bool {
_, ok := mp[element]
return ok
}
|
性能比较
测试 30 个元素结果
plaintext: 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 个元素结果
plaintext: 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 的查询性能比较40
优化方案,首先看元素个数,其次看元素类型(这里指常见的 int/string)。
- 15 个以下,无论是 int 还是 string,建议用
slice
- 15 ~ 100 个,尽量转为 int ,如果不能转为 int 就用 map
- 100 个以上,果断用 map,int 和 string 都差不多
本文网址: https://golangnote.com/topic/309.html 转摘请注明来源