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

如在Python中:

if "x" in array: 
  # do something

当前回答

另一种选择是使用地图作为集合。你只使用键,并让值为布尔值,总是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)
        }
    }
}

这是在围棋场上

其他回答

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

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

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

在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
}

我在这里找到的

上面使用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

另一种选择是使用地图作为集合。你只使用键,并让值为布尔值,总是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语句是最好的方法。