是否有类似于Go中的slice.contains(object)方法,而无需在slice中逐个搜索每个元素?
当前回答
从Go 1.18开始,你可以使用slices包——特别是泛型Contains函数: https://pkg.go.dev/golang.org/x/exp/slices。
go get golang.org/x/exp/slices
import "golang.org/x/exp/slices"
things := []string{"foo", "bar", "baz"}
slices.Contains(things, "foo") // true
请注意,由于这是在标准库之外的一个实验包,所以它不绑定到Go 1兼容性承诺™,并且在正式添加到标准库之前可能会更改。
其他回答
这可能会被认为有点“粗糙”,但根据切片的大小和内容,您可以将切片连接在一起并进行字符串搜索。
例如,您有一个包含单个单词值的切片(例如:“是”,“不是”,“可能”)。这些结果被追加到一个片中。如果您想检查此片是否包含任何“可能”结果,您可以使用
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
这是否合适取决于切片的大小和成员的长度。对于较大的切片或较长的值,可能存在性能或适用性问题,但对于较小的有限大小的切片和简单的值,这是实现所需结果的有效一行程序。
我使用reflect包创建了以下Contains函数。 此函数可用于各种类型,如int32或struct等。
// Contains returns true if an element is present in a slice
func Contains(list interface{}, elem interface{}) bool {
listV := reflect.ValueOf(list)
if listV.Kind() == reflect.Slice {
for i := 0; i < listV.Len(); i++ {
item := listV.Index(i).Interface()
target := reflect.ValueOf(elem).Convert(reflect.TypeOf(item)).Interface()
if ok := reflect.DeepEqual(item, target); ok {
return true
}
}
}
return false
}
contains函数的用法如下
// slice of int32
containsInt32 := Contains([]int32{1, 2, 3, 4, 5}, 3)
fmt.Println("contains int32:", containsInt32)
// slice of float64
containsFloat64 := Contains([]float64{1.1, 2.2, 3.3, 4.4, 5.5}, 4.4)
fmt.Println("contains float64:", containsFloat64)
// slice of struct
type item struct {
ID string
Name string
}
list := []item{
item{
ID: "1",
Name: "test1",
},
item{
ID: "2",
Name: "test2",
},
item{
ID: "3",
Name: "test3",
},
}
target := item{
ID: "2",
Name: "test2",
}
containsStruct := Contains(list, target)
fmt.Println("contains struct:", containsStruct)
// Output:
// contains int32: true
// contains float64: true
// contains struct: true
详情请点击此处: https://github.com/glassonion1/xgo/blob/main/contains.go
相比使用切片,map可能是更好的解决方案。
简单的例子:
package main
import "fmt"
func contains(slice []string, item string) bool {
set := make(map[string]struct{}, len(slice))
for _, s := range slice {
set[s] = struct{}{}
}
_, ok := set[item]
return ok
}
func main() {
s := []string{"a", "b"}
s1 := "a"
fmt.Println(contains(s, s1))
}
http://play.golang.org/p/CEG6cu4JTf
Mostafa已经指出,编写这样的方法很简单,mkb提示您使用排序包中的二进制搜索。但是如果您要做很多这样的包含检查,您也可以考虑使用地图代替。
通过使用value (ok:= yourmap[key]习语)来检查特定的映射键是否存在是很简单的。因为你对这个值不感兴趣,你也可以创建一个map[string]struct{}。在这里使用空结构体{}的好处是它不需要任何额外的空间,Go的内部映射类型针对这种值进行了优化。因此,map[string] struct{}是Go世界中集合的流行选择。
我认为map[x]bool比map[x]struct{}更有用。
为不存在的项索引映射将返回false。所以不是_,好的:= m[X],你可以说m[X]。
这使得在表达式中嵌套包含测试变得很容易。