有没有一种习惯用法可以在Go语言的切片中实现“in”操作?

huangapple go评论71阅读模式
英文:

Is there an idiomatic way to do "in" for golang slices

问题

我想检查一个值是否在值的切片中。实现这个的最佳方法是什么?
类似以下的方式:

if "foo" in []string{"foo", "bar"}...

我写了下面的代码,但不确定它是否符合惯用写法(我是 Go 语言的新手):

// 将特定类型的切片或数组转换为 interface{} 类型的数组
func ToIntf(s interface{}) []interface{} {
    v := reflect.ValueOf(s)
    // 不需要检查,如果它不是切片或数组,我们希望引发 panic
    intf := make([]interface{}, v.Len())
    for i := 0; i < v.Len(); i++ {
        intf[i] = v.Index(i).Interface()
    }
    return intf
}
func In(s []interface{}, val interface{}) bool {
    for _, v := range s {
        if v == val {
            return true
        }
    }
    return false
}

因此,为了使用这个,这是我写的一个测试方法。

func TestIn(t *testing.T) {
    s := []string{"foo", "bar", "kuku", "kiki"}
    for _, v := range s {
        if !In(ToIntf(s), v) {
            t.Error("应该存在")
        }
    }
    if In(ToIntf(s), "foobar") {
        t.Error("不应该存在")
    }
}
英文:

I would like to check if a value is in a slice of values. What is the best way to achieve this?
Something like the following:

if &quot;foo&quot; in []string{&quot;foo&quot;, &quot;bar&quot;}...

I've written the following code but not sure how idiomatic it is (golang newbie):

// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
    v := reflect.ValueOf(s)
    // There is no need to check, we want to panic if it&#39;s not slice or array
    intf := make([]interface{}, v.Len())
    for i := 0; i &lt; v.Len(); i++ {
        intf[i] = v.Index(i).Interface()
    }
    return intf
}
func In(s []interface{}, val interface{}) bool {
    for _, v := range s {
        if v == val {
            return true
        }
    }
    return false
}

So, to use this, here is a test method I wrote.

func TestIn(t *testing.T) {
    s := []string{&quot;foo&quot;, &quot;bar&quot;, &quot;kuku&quot;, &quot;kiki&quot;}
    for _, v := range s {
        if !In(ToIntf(s), v) {
            t.Error(&quot;Should be in&quot;)
        }
    }
    if In(ToIntf(s), &quot;foobar&quot;) {
        t.Error(&quot;Should not be in&quot;)
    }
}

答案1

得分: 8

在Go语言中,对于可以用简单循环表达的函数,惯用的方式就是这样实现。例如,你的方法可以这样写:

for _, value := range slice {
    if value == var {
        doSomething()
    }
}

显然,这种方式更冗长,但只有在你试图在Go中翻译 language or choice here 时才会如此。

使用反射的缺点是,性能会受到影响,而且并不比将代码编写为与搜索集成而不仅仅是将其视为条件更简单。

英文:

The idiomatic way, in go, for functions that can be expressed with a simple loop, to be implemented that way. Your method, for example, could be written that way:

for _, value := range slice {
    if value == var {
        doSomething()
    }
}

Obviously, it is somewhat more verbose, but that only if you try to translate language or choice here in go.

The downside of doing reflection is that you botch performances without being that simpler than if you write your code to integrate to the search rather than simply considering it a condition.

答案2

得分: 0

如果你需要一种廉价的方法来频繁检查这个(如果你需要经常检查它),我建议使用一个映射(map)来进行更便宜的查找,就像这样:

type Foo string

var sl []string
var m map[string]int

//插入
sl = append(sl, "bar")
m["bar"] += 1

//删除,例如在位置i
m[sl[i]] -= 1
sl[len(sl)-1], sl[:len(sl)-1]

//测试
if count := m["abc"]; count > 0 {
    // "abc"在sl中
}

当然,如果你在切片中更改了某些内容,这两种方法都会增加开销。这取决于你的情况。

如果你的切片不会改变,并且你将进行大量的“in”测试,你可以构建一个更简单的映射(map)来实现:

m := make(map[string]struct{}, len(sl))
for _, value := range sl {
    m[value] = struct{}{}
}

//测试
if _, ok := m["abc"]; ok {
    // "abc"在sl中
}
英文:

if you need a cheap way to check this (if you have to check it often) i would use a map for cheaper lookups. like this:

type Foo string

var sl []string
var m map[string]int

//insert
sl = append(sl, &quot;bar&quot;)
m[&quot;bar&quot;] += 1

// delete ,e.g at position i
m[sl[i]] -= 1
sl[len(sl)-1], s[:len(sl)-1]


//test
if count := m[&quot;abc&quot;]; count&gt;0 {
 // &quot;abc&quot; in sl 
}

Of course both will add overhead if you change something in the slice. That would depend on your case.

If your slice does not change, and you will do a lot of "in" testing you could build an easier map for that:

m := make(map[string]struct{}, len(sl))
for _, value := range sl {
    m[value] = struct{}
}

//test 

if _, ok := m[&quot;abc&quot;]; ok {
  // &quot;abc&quot; is in sl
}

huangapple
  • 本文由 发表于 2015年3月14日 04:35:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/29041494.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定