web-dev-qa-db-ja.com

スライスのメソッドを含みます

スライスの各要素を検索しなくても、Goのslice.contains(object)メソッドに似たものはありますか?

146
vosmith

Mostafaはすでにそのような方法は書くのが簡単であることをすでに指摘していました、そしてmkbはあなたにsortパッケージからの二分探索を使うヒントを与えました。しかし、そのような多くの包含チェックを実行しようとしている場合は、代わりにマップの使用を検討することもできます。

value, ok := yourmap[key]イディオムを使用して特定のマップキーが存在するかどうかを確認するのは簡単です。値には興味がないので、例えばmap[string]struct{}を作成することもできます。ここで空のstruct{}を使用すると、追加のスペースが不要になり、Goの内部マップタイプがそのような値に最適化されるという利点があります。そのため、Goの世界ではmap[string] struct{}がセットの人気のある選択肢です。

185
tux21b

いいえ、そのようなメソッドは存在しませんが、書くのは簡単です:

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

そのルックアップがコードの重要な部分である場合はマップを使用できますが、マップにもコストがかかります。

130
Mostafa

スライスがソートされている場合は、 sortパッケージ に実装されているバイナリ検索があります。

12
mkb

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))

}

http://play.golang.org/p/CEG6cu4JTf

7
holys

具象型がスライスであるインタフェースを反復処理するには、reflectパッケージを使用します。

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

5
Ethan Kennedy

ジェネリックがここで必要とされるのかわからない。あなたはただあなたの望む行動のための契約が必要です。例えば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
}
3
JonPen
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
}
2
Jim Hsiang

キーに基づいてアイテムを見つけるためにマップを使用するのが現実的でない場合は、 goderive ツールを検討することができます。 Goderiveはcontainsメソッドの型固有の実装を生成し、コードを読みやすく効率的にします。

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 ./...を実行してください。

このメソッドはderiveContainsに対して生成されます。

func deriveContainsFoo(list []Foo, item Foo) bool {
    for _, v := range list {
        if v == item {
            return true
        }
    }
    return false
}

Goderiveは、関数型プログラミングスタイルをそのまま適用するための、他の便利なヘルパーメソッドをいくつかサポートしています。