如何检查x是否在一个数组中,而不遍历整个数组,使用Go?语言中有这样的结构吗?

如在Python中:

if "x" in array: 
  # do something

当前回答

上面使用sort的例子很接近,但是在字符串的情况下只需使用SearchString:

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.SearchStrings(files, target)
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

https://golang.org/pkg/sort/#SearchStrings

其他回答

在Go 1.18+中,您现在可以声明泛型Contains函数,该函数也在实验性slice函数中实现。它适用于任何类似的类型

func Contains[T comparable](arr []T, x T) bool {
    for _, v := range arr {
        if v == x {
            return true
        }
    }
    return false
}

像这样使用它:

if Contains(arr, "x") {
    // do something
}
// or
if slices.Contains(arr, "x") {
    // do something
}

我在这里找到的

如果列表包含静态值,则另一种解决方案。

例:从有效值列表中检查有效值:

func IsValidCategory(category string) bool {
    switch category {
    case
        "auto",
        "news",
        "sport",
        "music":
        return true
    }
    return false
}

另一种选择是使用地图作为集合。你只使用键,并让值为布尔值,总是true。然后,您可以轻松地检查映射是否包含键。如果你需要一个集合的行为,这很有用,如果你多次添加一个值,它只在集合中出现一次。

这是一个简单的例子,我添加随机数作为键映射。如果相同的数字生成了不止一次,那也没关系,它只会在最终地图中出现一次。然后我使用一个简单的if检查来查看一个键是否在映射中。

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var MAX int = 10

    m := make(map[int]bool)

    for i := 0; i <= MAX; i++ {
        m[rand.Intn(MAX)] = true
    }

    for i := 0; i <= MAX; i++ {
        if _, ok := m[i]; ok {
            fmt.Printf("%v is in map\n", i)
        } else {
            fmt.Printf("%v is not in map\n", i)
        }
    }
}

这是在围棋场上

我也有一个类似的问题,并决定尝试一下这篇文章中的一些建议。

我已经对3种查找类型的最佳和最差情况进行了基准测试:

使用地图 使用列表 使用switch语句

下面是函数代码:

func belongsToMap(lookup string) bool {
list := map[string]bool{
    "900898296857": true,
    "900898302052": true,
    "900898296492": true,
    "900898296850": true,
    "900898296703": true,
    "900898296633": true,
    "900898296613": true,
    "900898296615": true,
    "900898296620": true,
    "900898296636": true,
}
if _, ok := list[lookup]; ok {
    return true
} else {
    return false
}
}


func belongsToList(lookup string) bool {
list := []string{
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636",
}
for _, val := range list {
    if val == lookup {
        return true
    }
}
return false
}

func belongsToSwitch(lookup string) bool {
switch lookup {
case
    "900898296857",
    "900898302052",
    "900898296492",
    "900898296850",
    "900898296703",
    "900898296633",
    "900898296613",
    "900898296615",
    "900898296620",
    "900898296636":
    return true
}
return false
}

最好的情况是选择列表中的第一项,最坏的情况是使用不存在的值。

以下是调查结果:

BenchmarkBelongsToMapWorstCase-4         2000000           787 ns/op
BenchmarkBelongsToSwitchWorstCase-4     2000000000           0.35 ns/op
BenchmarkBelongsToListWorstCase-4       100000000           14.7 ns/op
BenchmarkBelongsToMapBestCase-4          2000000           683 ns/op
BenchmarkBelongsToSwitchBestCase-4      100000000           10.6 ns/op
BenchmarkBelongsToListBestCase-4        100000000           10.4 ns/op

Switch一路胜出,最坏的情况比最好的情况快得多。

地图是最差的,列表更接近开关。

所以寓意是: 如果你有一个静态的,相当小的列表,switch语句是最好的方法。

这段话摘自《Go编程:为21世纪创建应用程序》一书:

Using a simple linear search like this is the only option for unsorted data and is fine for small slices (up to hundreds of items). But for larger slices—especially if we are performing searches repeatedly—the linear search is very inefficient, on average requiring half the items to be compared each time. Go provides a sort.Search() method which uses the binary search algorithm: This requires the comparison of only log2(n) items (where n is the number of items) each time. To put this in perspective, a linear search of 1000000 items requires 500000 comparisons on average, with a worst case of 1000000 comparisons; a binary search needs at most 20 comparisons, even in the worst case.

files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.Search(len(files),
    func(i int) bool { return files[i] >= target })
if i < len(files) && files[i] == target {
    fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}

https://play.golang.org/p/UIndYQ8FeW