检查一个值是否在列表中。

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

Check if a value is in a list

问题

Go语言有类似于Python的in关键字吗?我想要检查一个值是否在列表中。

例如在Python中:

x = 'red'

if x in ['red', 'green', 'yellow', 'blue']:
    print("found")
else:
    print("not found")

在Go语言中,我想到了使用集合的习惯用法,但我认为这不是理想的,因为我必须指定一个我不使用的int值。

x := "red"

valid := map[string]int{"red": 0, "green": 0, "yellow": 0, "blue": 0}

if _, ok := valid[x]; ok {
    fmt.Println("found")
} else {
    fmt.Println("not found")
}

我了解到拥有一个in关键字可能与泛型有关。是否有一种使用go generate或其他方式实现这个的方法?

英文:

Does Go have something similar to Python's in keyword? I want to check if a value is in a list.

For example in Python:

x = 'red'

if x in ['red', 'green', 'yellow', 'blue']:
    print "found"
else:
    print "not found"

In Go I've come up with using the set idiom but I don't think it's ideal as I have to specify a int value that I'm not using.

x := "red"

valid := map[string]int{"red": 0, "green": 0,"yellow": 0, "blue": 0}

if _, ok := valid[x]; ok {
	fmt.Println("found")
} else {
	fmt.Println("not found")
}

I understand having an in keyword is probably related to generics. Is there a way to do this using go generate or something?

答案1

得分: 22

你可以使用map[string]bool作为集合。当进行测试时,如果键不在映射中,将返回bool类型的零值,即false

因此,将有效值作为键填充到映射中,并将值设置为true。如果测试的键值在映射中,其存储的true值将作为结果返回。如果测试的键值不在映射中,则返回值类型的零值,即false

使用这种方法,测试变得非常简单:

valid := map[string]bool{"red": true, "green": true, "yellow": true, "blue": true}

if valid[x] {
    fmt.Println("found")
} else {
    fmt.Println("not found")
}

Go Playground上尝试一下(使用下面提到的变体)。

这在博客文章Go maps in action: Exploiting zero values中有提到。

注意:

如果有很多有效值,由于要存储在映射中的所有值都是true,可以使用切片列出有效值,并使用for range循环初始化映射,类似于以下示例:

for _, v := range []string{"red", "green", "yellow", "blue"} {
    valid[v] = true
}

注意2:

如果你不想使用for range循环初始化,仍然可以通过创建一个无类型(或bool类型)的单字母const来进行优化:

const t = true
valid := map[string]bool{"red": t, "green": t, "yellow": t, "blue": t}
英文:

You can use a map[string]bool as a set. When testing and a key is not in the map, the zero value for bool is returned which is false.

So fill the map with the valid values as keys and true as value. If a tested key-value is in the map, its stored true value will be the result. If a tested key-value is not in the map, the zero value for the value type is returned which is false.

Using this, the test becomes this simple:

valid := map[string]bool{"red": true, "green": true, "yellow": true, "blue": true}

if valid[x] {
	fmt.Println("found")
} else {
	fmt.Println("not found")
}

Try it on the Go Playground (with the variants mentioned below).

This is mentioned in the blog post: Go maps in action: Exploiting zero values

Note:

If you have many valid values, since all the values to be stored in the map are true, it may be more compact to use a slice to list the valid values and use a for range loop to initialize your map, something like this:

for _, v := range []string{"red", "green", "yellow", "blue"} {
	valid[v] = true
}

Note #2:

If you don't want to go with the for range loop initialization, you can still optimize it a little by creating an untyped (or bool-typed) one-letter const:

const t = true
valid := map[string]bool{"red": t, "green": t, "yellow": t, "blue": t}

答案2

得分: 1

我认为另一个答案中的map[string]bool是一个不错的选择。另一种方法是使用map[string]struct{},它使用的内存稍微少一些:

package main

func main() {
   x, valid := "red", map[string]struct{}{
      "red": {}, "green": {}, "yellow": {}, "blue": {},
   }
   if _, ok := valid[x]; ok {
      println("找到了")
   } else {
      println("未找到")
   }
}

你也可以将其封装在一个类型中:

package main

type set map[string]struct{}

func newSet(slice []string) set {
   s := make(set)
   for _, each := range slice {
      s[each] = struct{}{}
   }
   return s
}

func (s set) has(v string) bool {
   _, ok := s[v]
   return ok
}

func main() {
   x := "red"
   if newSet([]string{"red", "green", "yellow", "blue"}).has(x) {
      println("找到了")
   } else {
      println("未找到")
   }
}
英文:

I think map[string]bool in the other answer is a good option. Another method
is map[string]struct{}, which uses slightly less memory:

package main

func main() {
   x, valid := "red", map[string]struct{}{
      "red": {}, "green": {}, "yellow": {}, "blue": {},
   }
   if _, ok := valid[x]; ok {
      println("found")
   } else {
      println("not found")
   }
}

You could also wrap it in a type:

package main

type set map[string]struct{}

func newSet(slice []string) set {
   s := make(set)
   for _, each := range slice {
      s[each] = struct{}{}
   }
   return s
}

func (s set) has(v string) bool {
   _, ok := s[v]
   return ok
}

func main() {
   x := "red"
   if newSet([]string{"red", "green", "yellow", "blue"}).has(x) {
      println("found")
   } else {
      println("not found")
   }
}

答案3

得分: 0

在Go语言中使用泛型(generics)>= 1.18

package main

import "fmt"

// In是一个泛型函数,用于检查给定的元素是否存在于可比较类型的切片中。如果找到该元素,则返回true,否则返回false。
func In[Item comparable](items []Item, item Item) bool {
	for i := 0; i < len(items); i++ {
		if items[i] == item {
			return true
		}
	}
	return false
}

func main() {
	fmt.Println(In([]int{1, 2, 3, 4, 5}, 3))
}
true

Go Playground链接:https://go.dev/play/p/ovhlcaBz0Uc

英文:

Using generics in Go >= 1.18

package main

import &quot;fmt&quot;

// In is a generic function that checks if a given item exists in a slice of
// items of a comparable type. It returns true if the item is found, otherwise
// it returns false.
func In[Item comparable](items []Item, item Item) bool {
	for i := 0; i &lt; len(items); i++ {
		if items[i] == item {
			return true
		}
	}
	return false
}

func main() {
	fmt.Println(In([]int{1, 2, 3, 4, 5}, 3))
}
true

Go Playground https://go.dev/play/p/ovhlcaBz0Uc

huangapple
  • 本文由 发表于 2015年5月26日 15:41:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/30452433.html
匿名

发表评论

匿名网友

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

确定