func InIntSliceSortedFunc(haystack []int) func(int) bool {
sort.Ints(haystack)
return func(needle int) bool {
index := sort.SearchInts(haystack, needle)
return index < len(haystack) && haystack[index] == needle
}
}
上面的实现,我们通过调用 InIntSliceSortedFunc 对 haystack 切片排序,并返回一个可多次使用的函数。
使用案例如下:
in := gotin.InIntSliceSortedFunc(haystack)
for i := 0; i<maxNeedle; i++ {
if in(i) {
fmt.Printf("%d is in %v", i, haystack)
}
}
二分查找的方式有什么不足呢?
我想到的重要一点,要实现二分查找,元素必须是可排序的,如 int,string,float 类型。而对于结构体、切片、数组、映射等类型,使用起来就不是那么方便,当然,如果要用,也是可以的,不过需要我们进行一些适当扩展,按指定标准排序,比如结构的某个成员。
到此,二分查找的 in 实现就介绍完毕了。
map key
本节介绍 map key 方式。它的算法复杂度是 O1,无论数据量多大,查询性能始终不变。它主要依赖的是 Go 中的 map 数据类型,通过 hash map 直接检查 key 是否存在,算法大家应该都比较熟悉,通过 key 可直接映射到索引位置。
我们常会用到这个方法。
_, ok := m[k]
if ok {
fmt.Println("Found")
}
那么它和 in 如何结合呢?一个案例就说明白了这个问题。
假设,我们有一个 []int 类型变量,如下:
s := []int{1, 2, 3}
为了使用 map 的能力检查某个元素是否存在,可以将 s 转化 map[int]struct{}。
m := map[interface{}]struct{}{
1: struct{}{},
2: struct{}{},
3: struct{}{},
4: struct{}{},
}
如果检查某个元素是否存在,只需要通过如下写法即可确定:
k := 4
if _, ok := m[k]; ok {
fmt.Printf("%d is foundn", k)
}
是不是非常简单?
补充一点,关于这里为什么使用 struct{},可以阅读我之前写的一篇关于Go 中如何使用 set 的文章。
按照这个思路,实现函数如下:
func MapKeyInIntSlice(haystack []int, needle int) bool {
set := make(map[int]struct{})
for _ , e := range haystack {
set[e] = struct{}{}
}
_, ok := set[needle]
return ok
}
实现起来不难,但和二分查找有着同样的问题,开始要做数据处理,将 slice 转化为 map。如果是每次数据相同,稍微修改下它的实现。
func InIntSliceMapKeyFunc(haystack []int) func(int) bool {
set := make(map[int]struct{})
for _ , e := range haystack {
set[e] = struct{}{}
}
return func(needle int) bool {
_, ok := set[needle]
return ok
}
}
对于相同的数据,它会返回一个可多次使用的 in 函数,一个使用案例如下:









