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

255 if-statement go

如果没有遍历整个数组,我可以检查xGo中的数组吗?

像Python一样: if "x" in array: ...

and*_*olm 309

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

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

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

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

  • 它可以使用反射包来完成,但效率相当低(可能与用Python这样的动态语言编写它一样慢).除此之外,没有.当人们说Go没有泛型时,这就是人们的意思. (23认同)
  • 地图不是以大多数语言排序的 - 这与地图数据结构(hashmap)的课程相同. (6认同)
  • 有没有办法在没有指定类型的情况下执行此操作?让我们说如果我只想要一个通用的needleInHaystack(针,干草堆)功能,而不是每种类型的单独方法 (4认同)
  • 你也不能在Javascript中对地图(对象)进行排序.这是一个v8*bug*,对象按字母顺序排序返回值. (3认同)
  • 偶然发现此答案的任何人都必须注意,您无法对地图进行排序。使用go地图的不利之处很大。 (2认同)
  • @Hejazzman 除了哈希映射之外,许多其他主流语言也有排序映射,例如 C++ 中的“map”和 Java 中的“SortedMap” (2认同)
  • 我几乎每天都会发现 Go 中我不喜欢的新东西。感觉就像我们后退了一步 (2认同)

小智 85

列表包含静态值的另一种解决方案.

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

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

  • 是的,如果您的"有效值"来自数据库怎么办? (10认同)
  • 与最佳答案相比,这很简洁 (4认同)
  • @RonanDejhero然后我可以使用WHERE:myValue IN(子查询):) (2认同)

小智 48

这是"编程进入:创造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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 只有在重复搜索时才有意义.否则,排序和二分搜索的复杂度为n*log(n)*log(n),而线性搜索只有n. (8认同)
  • 它实际上只是“n*log(n) + log(n)”,因为它是两个连续的独立操作 (6认同)

小智 23

上面使用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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这个答案看起来像是下面答案的信息较少的复制粘贴,它发生在这个答案之前。 (3认同)

小智 19

刚刚有类似的问题,并决定尝试在这个线程中的一些建议.

我已经对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
}
Run Code Online (Sandbox Code Playgroud)

最佳案例场景选择列表中的第一项,最坏情况下使用不存在的值.

结果如下:

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语句就是你要走的路.

  • 没有什么比提供解决方案并使用基准将其与最“明显”的其他解决方案进行比较 - 用_数据_支持你的建议,而不是猜测!谢谢你——我会坚持使用开关,因为我有固定的、静态的支票数量...... (4认同)
  • 这个基准有相当严重的缺陷。您正在初始化要在进行基准测试的相同方法中搜索的结构。我重新实现了这个并将这些列表和映射的初始化放入“func Bench...”方法中。当不包括映射初始化或切片初始化时,当要搜索的结构中有 10 个键时,搜索映射的速度会快两倍以上。随着条目数量的增加,这种差异对于切片来说只会变得更糟。 (3认同)

Ica*_*sNM 12

这与 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!")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


go *_* jo 8

在 Go 1.18+ 1.21+ 中,您现在可以声明泛型Contains函数或在实验切片包 中导入内置切片包。它适用于任何类似类型

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

并像这样使用它:

if Contains(arr, "x") {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

或通过导入

// func[S ~[]E, E comparable](s S, v E) bool
if slices.Contains(arr, "x") {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

我在这里找到的


nob*_*led 7

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

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

在这里,它是在游乐场