如何检查x是否在一个数组中,而不遍历整个数组,使用Go?语言中有这样的结构吗?
如在Python中:
if "x" in array:
# do something
如何检查x是否在一个数组中,而不遍历整个数组,使用Go?语言中有这样的结构吗?
如在Python中:
if "x" in array:
# do something
当前回答
在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
}
我在这里找到的
其他回答
在Go中没有内置的操作符来做这件事。你需要遍历数组。你可以编写自己的函数来实现,就像这样:
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
或者在Go 1.18或更新版本中,你可以使用切片。包含(来自golang.org/x/exp/slices)。
如果你想在不遍历整个列表的情况下检查成员关系,你需要使用map而不是数组或slice,如下所示:
visitedURL := map[string]bool {
"http://www.google.com": true,
"https://paypal.com": true,
}
if visitedURL[thisSite] {
fmt.Println("Already been here.")
}
这段话摘自《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
另一种选择是使用地图作为集合。你只使用键,并让值为布尔值,总是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语句是最好的方法。
上面使用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