2013-03-10 112 views
153

没有遍历整个数组如何检查数组中的'x'是否在Go?Golang有没有像Python那样的“if x in”构造?

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

+2

可能http://stackoverflow.com/q/8307478/180100 – 2013-03-10 15:22:02

+4

据我所知,没有对在去速记的欺骗。在内部,python也遍历数组,没有任何回转。 – Danish94 2013-03-10 15:24:34

+3

顺便说一句,对此的一个重要提示是*没有办法做到这一点(如你所要求的)“** [w]没有**迭代整个阵列”。使这样的循环显式化(或在诸如'strings.Index'之类的函数后面)有助于使代码更加明显。我的印象是,也许你认为Python的'阵列:'正在做一些快速/魔术。 AFAIK它不是。使循环明确有助于使作者(和所有读者)了解并考虑其他实现(例如地图)。 – 2015-04-16 17:32:22

回答

197

没有内置运营商做的围棋。你需要遍历数组。您可以编写自己的函数来做到这一点,就像这样:

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

有没有办法做到这一点,而不指定类型?让我们假设如果我只需要一根普通needleInHaystack(needle,haystack)函数而不用每种类型的单独方法 – Allen 2015-05-13 04:33:05

+9

它可以使用反射包来完成,但效率相当低(可能大概就像写出来一样慢像Python这样的动态语言)。除此之外,没有。当他们说Go没有泛型时,这就是人们的意思。 – andybalholm 2015-05-13 15:44:57

+1

任何人偶然发现这个答案必须注意,你不能排序地图。使用go map很不好。 – khuderm 2015-11-12 21:10:02

34

这是从书帖“规划中去:创建21世纪的应用程序”:

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

转到提供了使用二进制搜索算法 一个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

+2

这只有在重复搜索时才有意义。否则,对于排序和二进制搜索,您的复杂度为n * log(n)* log(n),而对于线性搜索,则只有n。 – christian 2017-10-17 16:17:53

40

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

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

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

是的,如果你的“有效值”来自数据库呢? – 2016-08-26 08:34:53

14

上面的例子使用的排序是接近的,但在字符串的情况下,简单地使用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

+0

这个答案看起来像下面的答案的一个较少的信息复制粘贴,发生在这个答案之前。 – cytinus 2017-09-26 05:38:34

+0

@cytinus你指的是什么答案?这是我看到的基于'sort.SearchStrings'的唯一一个。 – akim 2017-09-27 11:57:26

+0

我通过大片重复搜索获得了100倍的加速比。 – Xeoncross 2018-01-31 15:11:24

5

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

下面是一个简单的例子,我将随机数作为键添加到地图中。如果同一个号码不止一次生成,则无关紧要,它只会出现在最终的地图中一次。然后,我使用一个简单的检查来查看某个键是否在地图中。

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

相关问题