go 判断元素是否在slice_Go 中 slice 的 In 功能实现探索

本文探讨了Go语言中为何没有类似Python的`in`功能,并提出了三种实现方式:遍历、二分查找和利用map key。通过代码示例展示了每种方法的实现细节和适用场景,同时进行了性能测试,结果显示在不同数据量下,各种方法的性能表现各有优势。最后,总结了在不同场景下选择合适实现方式的重要性。
摘要由CSDN通过智能技术生成

2d50a7e1522be3e9b0858974ba4ce1aa.png

之前在知乎看到一个问题:为什么 Golang 没有像 Python 中 in 一样的功能?于是,搜了下这个问题,发现还是有不少人有这样的疑问。

今天来谈谈这个话题。

in 是一个很常用的功能,有些语言中可能也称为 contains,虽然不同语言的表示不同,但基本都是有的。不过可惜的是,Go 却没有,它即没有提供类似 Python 操作符 in,也没有像其他语言那样提供这样的标准库函数,如 PHP 中 in_array。

Go 的哲学是追求少即是多。我想或许 Go 团队觉得这是一个实现起来不足为道的功能吧。

为何说微不足道?如果要自己实现,又该如何做呢?

我所想到的有三种实现方式,一是遍历,二是 sort 的二分查找,三是 map 的 key 索引。

本文相关源码已经上传在我的 github 上,poloxue/gotin。

遍历

遍历应该是我们最容易想到的最简单的实现方式。

示例如下:

func InIntSlice(haystack []int, needle int) bool {
    for _, e := range haystack {
        if e == needle {
            return true
        }
    }

    return false
}

上面演示了如何在一个 []int 类型变量中查找指定 int 是否存在的例子,是不是非常简单,由此我们也可以感受到我为什么说它实现起来微不足道。

这个例子有个缺陷,它只支持单一类型。如果要支持像解释语言一样的通用 in 功能,则需借助反射实现。

代码如下:

func In(haystack interface{}, needle interface{}) (bool, error) {
    sVal := reflect.ValueOf(haystack)
    kind := sVal.Kind()
    if kind == reflect.Slice || kind == reflect.Array {
        for i := 0; i < sVal.Len(); i++ {
            if sVal.Index(i).Interface() == needle {
                return true, nil
            }
        }

        return false, nil
    }

    return false, ErrUnSupportHaystack
}

为了更加通用,In 函数的输入参数 haystack 和 needle 都是 interface{} 类型。

简单说说输入参数都是 interface{} 的好处吧,主要有两点,如下:

其一,haystack 是 interface{} 类型,使 in 支持的类型不止于 slice,还包括 array。我们看到,函数内部通过反射对 haystack 进行了类型检查,支持 slice(切片)与 array(数组)。如果是其他类型则会提示错误,增加新的类型支持,如 map,其实也很简单。但不推荐这种方式,因为通过 _, ok := m[k] 的语法即可达到 in 的效果。

其二,haystack 是 interface{},则 []interface{} 也满足要求,并且 needle 是 interface{}。如此一来,我们就可以实现类似解释型语言一样的效果了。

怎么理解?直接示例说明,如下:

gotin.In([]interface{}{1, "two", 3}, "two")

haystack 是 []interface{}{1, "two", 3},而且 needle 是 interface{},此时的值是 "two"。如此看起来,是不是实现了解释型语言中,元素可以是任意类型,不必完全相同效果。如此一来,我们就可以肆意妄为的使用了。

但有一点要说明,In 函数的实现中有这样一段代码:

if sVal.Index(i).Int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值