关于go:包含切片的方法

Contains method for a slice

Go中是否有类似于slice.contains(object)方法的东西,而不必搜索切片中的每个元素?


mostafa已经指出,这样的方法编写起来很简单,mkb提示您使用排序包中的二进制搜索。但是如果你要做很多这样的包含检查,你也可以考虑使用一个地图代替。

使用value, ok := yourmap[key]习惯用法检查特定的映射键是否存在是很简单的。因为您对价值不感兴趣,所以您也可以创建一个map[string]struct{}。在这里使用空的struct{}有一个优点,即它不需要任何额外的空间,Go的内部映射类型针对此类值进行了优化。因此,map[string] struct{}是围棋世界中布景的流行选择。


不,这种方法不存在,但写起来很简单:

1
2
3
4
5
6
7
8
func contains(s []int, e int) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

如果查找是代码的重要组成部分,则可以使用映射,但映射也有成本。


如果对切片进行排序,则在sort包中实现二进制搜索。


与使用slice不同,map可能是更好的解决方案。

简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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


您可以使用reflect包在具体类型为slice的接口上迭代:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
}

https://play.golang.org/p/jl5ud7ycnq


不确定这里是否需要泛型。你只是需要一份合同来满足你想要的行为。如果您希望自己的对象在集合中表现出自己的行为,那么执行以下操作只需在其他语言中执行,例如,通过重写equals()和gethashcode()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}


如果不能使用基于键的地图查找项目,可以考虑使用Goderive工具。Goderive生成一个特定于类型的contains方法实现,使代码既可读又高效。

例子;

1
2
3
4
5
6
7
8
9
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
  • 在工作区文件夹中运行goderive ./...
  • 小精灵

    将为派生容器生成此方法:

    1
    2
    3
    4
    5
    6
    7
    8
    func deriveContainsFoo(list []Foo, item Foo) bool {
        for _, v := range list {
            if v == item {
                return true
            }
        }
        return false
    }

    Goderive支持许多其他有用的助手方法来在Go中应用函数式编程风格。