2023-11-10 05:01:49

包含片的方法

是否有类似于Go中的slice.contains(object)方法,而无需在slice中逐个搜索每个元素?


当前回答

我使用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

在Go 1.18+中,我们可以使用泛型。

func Contains[T comparable](s []T, e T) bool {
    for _, v := range s {
        if v == e {
            return true
        }
    }
    return false
}

如果切片已排序,则排序包中实现了二进制搜索。

不,这样的方法不存在,但是写起来很简单:

func contains(s []int, e int) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

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

如果使用地图根据钥匙查找物品是不可行的,你可以考虑使用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中应用函数式编程风格。