Go有“if in in”构造类似于Python吗?

时间:2013-03-10 15:15:57

标签: if-statement go

没有迭代整个数组,如何使用Go检查数组中的x?该语言是否有构造?

与Python类似:if "x" in array: ...

7 个答案:

答案 0 :(得分:269)

在Go中没有内置的操作符。您需要迭代数组。您可以编写自己的函数来执行此操作,如下所示:

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

如果您希望能够在不迭代整个列表的情况下检查成员资格,则需要使用地图而不是数组或切片,如下所示:

visitedURL := map[string]bool {
    "http://www.google.com": true,
    "https://paypal.com": true,
}
if visitedURL[thisSite] {
    fmt.Println("Already been here.")
}

答案 1 :(得分:74)

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

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

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

答案 2 :(得分:47)

这是引用本书"编程进入:创造21世纪的应用程序":

  

使用像这样的简单线性搜索是未排序的唯一选项   数据,适用于小切片(最多数百个项目)。但对于   更大的切片 - 特别是如果我们重复执行搜索 -   线性搜索效率非常低,平均需要一半的项目   每次比较。

     

Go提供了一个使用二进制搜索的sort.Search()方法   算法:这需要仅比较log2(n)项(其中n   是每次的项目数量。为了正确看待这一点,   线性搜索1000000个项目平均需要500000个比较,   最糟糕的情况是1000000比较;二进制搜索需要   大多数20次比较,即使是在最坏的情况下。

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

答案 3 :(得分:22)

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

答案 4 :(得分:13)

也有类似的问题,并决定尝试该线程中的一些建议。

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

  • 使用地图
  • 使用列表
  • 使用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语句是可行的方法。

答案 5 :(得分:6)

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

这是一个简单的例子,我将随机数作为键添加到地图中。如果多次生成相同的数字并不重要,它只会出现在最终的地图上一次。然后我使用一个简单的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)
        }
    }
}

Here it is on the go playground

答案 6 :(得分:6)

这与我对Python的“ in”运算符的自然感觉很接近。您必须定义自己的类型。然后,您可以通过添加行为类似您希望的“ has”之类的方法来扩展该类型的功能。

package main

import "fmt"

type StrSlice []string

func (list StrSlice) Has(a string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func main() {
    var testList = StrSlice{"The", "big", "dog", "has", "fleas"}

    if testList.Has("dog") {
        fmt.Println("Yay!")
    }
}

我有一个实用程序库,在其中为一些类型的切片定义了一些常见的东西,例如包含整数或我自己的其他结构的切片。

是的,它以线性时间运行,但这不是重点。关键是要问和学习Go具有和不具有的通用语言构造。这是一个很好的练习。这个答案是愚蠢还是有用,取决于读者。