スライスの各要素を検索しなくても、Goのslice.contains(object)
メソッドに似たものはありますか?
Mostafaはすでにそのような方法は書くのが簡単であることをすでに指摘していました、そしてmkbはあなたにsortパッケージからの二分探索を使うヒントを与えました。しかし、そのような多くの包含チェックを実行しようとしている場合は、代わりにマップの使用を検討することもできます。
value, ok := yourmap[key]
イディオムを使用して特定のマップキーが存在するかどうかを確認するのは簡単です。値には興味がないので、例えばmap[string]struct{}
を作成することもできます。ここで空のstruct{}
を使用すると、追加のスペースが不要になり、Goの内部マップタイプがそのような値に最適化されるという利点があります。そのため、Goの世界ではmap[string] struct{}
がセットの人気のある選択肢です。
いいえ、そのようなメソッドは存在しませんが、書くのは簡単です:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
そのルックアップがコードの重要な部分である場合はマップを使用できますが、マップにもコストがかかります。
スライスがソートされている場合は、 sort
パッケージ に実装されているバイナリ検索があります。
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))
}
具象型がスライスであるインタフェースを反復処理するには、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
}
ジェネリックがここで必要とされるのかわからない。あなたはただあなたの望む行動のための契約が必要です。例えば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
}
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メソッドの型固有の実装を生成し、コードを読みやすく効率的にします。
例
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は、関数型プログラミングスタイルをそのまま適用するための、他の便利なヘルパーメソッドをいくつかサポートしています。