是否有类似于Go中的slice.contains(object)方法,而无需在slice中逐个搜索每个元素?
当前回答
不确定这里是否需要泛型。你只需要为你想要的行为订立契约。如果您想让自己的对象在集合中表现自己,那么在其他语言中,通过重写Equals()和GetHashCode(),您必须做的事情不亚于下面所做的事情。
type Identifiable interface{
GetIdentity() string
}
func IsIdentical(this Identifiable, that Identifiable) bool{
return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}
func contains(s []Identifiable, e Identifiable) bool {
for _, a := range s {
if IsIdentical(a,e) {
return true
}
}
return false
}
其他回答
相比使用切片,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世界中集合的流行选择。
如果你有一个字节切片,你可以使用bytes包:
package main
import "bytes"
func contains(b []byte, sub byte) bool {
return bytes.Contains(b, []byte{sub})
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
或suffixarray包:
package main
import "index/suffixarray"
func contains(b []byte, sub byte) bool {
return suffixarray.New(b).Lookup([]byte{sub}, 1) != nil
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
如果你有一个int片,你可以使用intsets包:
package main
import "golang.org/x/tools/container/intsets"
func main() {
var s intsets.Sparse
for n := 10; n < 20; n++ {
s.Insert(n)
}
b := s.Has(16)
println(b)
}
https://golang.org/pkg/bytes https://golang.org/pkg/index/suffixarray https://pkg.go.dev/golang.org/x/tools/container/intsets
这可能会被认为有点“粗糙”,但根据切片的大小和内容,您可以将切片连接在一起并进行字符串搜索。
例如,您有一个包含单个单词值的切片(例如:“是”,“不是”,“可能”)。这些结果被追加到一个片中。如果您想检查此片是否包含任何“可能”结果,您可以使用
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
这是否合适取决于切片的大小和成员的长度。对于较大的切片或较长的值,可能存在性能或适用性问题,但对于较小的有限大小的切片和简单的值,这是实现所需结果的有效一行程序。
如果使用地图根据钥匙查找物品是不可行的,你可以考虑使用goderived工具。goderived生成包含方法的特定于类型的实现,使您的代码既可读又高效。
例子;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
生成派生econtainsfoo方法:
使用go get -u github.com/awalterschulze/goderive安装goderived 运行goderived。/…在工作区文件夹中
这个方法将为衍生的包含生成:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
goderived还支持很多其他有用的辅助方法,可以在go中应用函数式编程风格。