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