英文:
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 "fmt"
// 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 < 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论