Answers:
Mostafa已经指出,编写这种方法很简单,而mkb为您提供了使用sort包中的二进制搜索的提示。但是,如果要进行很多此类包含检查,则还可以考虑使用地图。
使用value, ok := yourmap[key]
惯用语检查特定的映射键是否存在很简单。由于您对值不感兴趣,因此也可以创建一个map[string]struct{}
例如。struct{}
在此处使用空值的优点是不需要任何额外的空间,并且Go的内部映射类型针对该类型的值进行了优化。因此,map[string] struct{}
在围棋世界中是流行的选择。
struct{}{}
以获取空结构的值,以便在想要添加元素时可以将其传递给地图。只需尝试一下,如果遇到任何问题,请随时提问。如果您更容易理解,也可以使用Mostafa的解决方案(除非您有大量数据)。
map[string] bool
相比map[string] struct{}
。map[string] struct{}
似乎是黑客,尤其是初始化一个空结构struct {}{}
不,这种方法不存在,但是编写起来很简单:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
如果该查找是代码的重要组成部分,则可以使用地图,但是地图也有成本。
interface{}
而不是使用slice
,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))
}
sliceToMap
完成所有准备工作的功能。之后,查询地图是简单而有效的。
该排序包提供了构建块,如果你的片进行排序,或者您愿意排序。
input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)
fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow")) // false
...
func contains(s []string, searchterm string) bool {
i := sort.SearchStrings(s, searchterm)
return i < len(s) && s[i] == searchterm
}
SearchString
承诺会返回the index to insert x if x is not present (it could be len(a))
,因此检查该字符串会发现字符串是否包含已排序的片。
O(n)
并且此解决方案可以做到O(n*log(n))
。
contains
是O(log(n))
,但是整体方法O(n*log(n))
归因于排序。
您可以使用反射包在具体类型为切片的接口上进行迭代:
func HasElem(s interface{}, elem interface{}) bool {
arrV := reflect.ValueOf(s)
if arrV.Kind() == reflect.Slice {
for i := 0; i < arrV.Len(); i++ {
// XXX - panics if slice element points to an unexported struct field
// see https://golang.org/pkg/reflect/#Value.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
如果使用地图基于键查找项目不可行,则可以考虑使用Goderive工具。Goderive生成包含方法的特定于类型的实现,使您的代码既可读又高效。
例;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
要生成deriveContainsFoo方法:
go get -u github.com/awalterschulze/goderive
goderive ./...
在您的工作区文件夹中运行此方法将为generateContains生成:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive支持许多其他有用的辅助方法,以在go中应用函数式编程样式。
func Contain(target interface{}, list interface{}) (bool, int) {
if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
listvalue := reflect.ValueOf(list)
for i := 0; i < listvalue.Len(); i++ {
if target == listvalue.Index(i).Interface() {
return true, i
}
}
}
if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
}
return false, -1
}
不确定此处是否需要泛型。您只需要为所需的行为订立合同即可。如果您希望自己的对象在集合中表现自己,例如通过覆盖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
}
Contains()
中实现List<T>
,因此您只需实现Equals()
该工作即可。
我用这些答案中的解决方案创建了一个非常简单的基准。
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
这不是一个真正的基准,因为起初,我没有插入太多元素,但可以随意进行分叉和更改。
它可能被认为有点“ hacky”,但是根据切片的大小和内容,您可以将切片连接在一起并进行字符串搜索。
例如,您有一个包含单个单词值的切片(例如,“是”,“否”,“也许”)。这些结果将附加到切片中。如果要检查此切片是否包含任何“也许”结果,则可以使用
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
这实际上是否合适取决于切片的大小及其成员的长度。大切片或长值可能存在性能或适用性问题,但对于有限大小和简单值的较小切片,它是实现所需结果的有效方法。
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
围棋风格:
func Contains(n int, match func(i int) bool) bool {
for i := 0; i < n; i++ {
if match(i) {
return true
}
}
return false
}
s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
return s[i] == "o"
})