检查一个值是否在列表中
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 中,我想到了使用 set 习语,但我认为这不是理想的,因为我必须指定一个我没有使用的 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 或其他方法来做到这一点?
您可以将 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 上试用(使用下面提到的变体)。
博客post中提到了这个: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}
我认为另一个答案中的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("found")
} else {
println("not found")
}
}
你也可以把它包装成一个类型:
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")
}
}
在 Go 中使用泛型 >= 1.18
package slice
func In[Item compareable](items []Item, item Item) bool {
for i := 0; i < len(items); i++ {
if items[i] == item {
return true
}
}
return false
}
package main
import "fmt"
import "slice"
func main() {
fmt.Println(slice.In([]int{1, 2, 3, 4, 5}, 3)
}
true
Go 是否有类似于 Python 的 in
关键字的东西?我想检查一个值是否在列表中。
例如 Python:
x = 'red'
if x in ['red', 'green', 'yellow', 'blue']:
print "found"
else:
print "not found"
在 Go 中,我想到了使用 set 习语,但我认为这不是理想的,因为我必须指定一个我没有使用的 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 或其他方法来做到这一点?
您可以将 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 上试用(使用下面提到的变体)。
博客post中提到了这个: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}
我认为另一个答案中的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("found")
} else {
println("not found")
}
}
你也可以把它包装成一个类型:
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")
}
}
在 Go 中使用泛型 >= 1.18
package slice
func In[Item compareable](items []Item, item Item) bool {
for i := 0; i < len(items); i++ {
if items[i] == item {
return true
}
}
return false
}
package main
import "fmt"
import "slice"
func main() {
fmt.Println(slice.In([]int{1, 2, 3, 4, 5}, 3)
}
true