1

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 "foo" in []string{"foo", "bar"}... 

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's not slice or array 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 } 

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

func TestIn(t *testing.T) { s := []string{"foo", "bar", "kuku", "kiki"} for _, v := range s { if !In(ToIntf(s), v) { t.Error("Should be in") } } if In(ToIntf(s), "foobar") { t.Error("Should not be in") } } 
1
  • 4
    From a performance standpoint I don't like it because it is adding a bunch of work through interface{} pointers that is pointless, aside from not having to write one copy of In() for each data type. Commented Mar 13, 2015 at 20:45

2 Answers 2

8

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Of course I agree regarding performance but not all code has to be "the most efficient" and if I know that the slice size will be very small I would prefer not to be that verbose.
PS - I just ran a short test on my laptop and for 10,000,000 slice of strings it takes less than a second. Now, consider the use case of me trying to check if a value is not in a list of values. Now, your code suddenly becomes: in := false for _, value := range slice { if value == var { in = true break } } if !in { doSomething() } Instead of: if !In(slice, val) {doSomething()}
0

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, "bar") m["bar"] += 1 // delete ,e.g at position i m[sl[i]] -= 1 sl[len(sl)-1], s[:len(sl)-1] //test if count := m["abc"]; count>0 { // "abc" 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["abc"]; ok { // "abc" is in sl } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.