回答:
Mostafaは、そのようなメソッドを書くのは簡単であることをすでに指摘しており、mkbは、sortパッケージのバイナリ検索を使用するためのヒントを与えてくれました。ただし、そのような多くのチェックが含まれる場合は、代わりにマップを使用することも検討してください。
value, ok := yourmap[key]
イディオムを使用して特定のマップキーが存在するかどうかを確認するのは簡単です。値に興味がないのでmap[string]struct{}
、たとえばを作成することもできます。struct{}
ここで空を使用すると、追加のスペースを必要とせず、Goの内部マップタイプがそのような値に最適化されるという利点があります。したがって、map[string] struct{}
Goの世界ではセットによく使用されます。
struct{}{}
、要素を追加するときにマップに渡すことができるように、空の構造体の値を取得するために書き込む必要があることにも注意してください。試してみてください。問題が発生した場合は、遠慮なく質問してください。モスタファのソリューションを使用することもできます(大量のデータがない場合)。
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
はreturnを約束する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は、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 ./...
ワークスペースフォルダーで実行するこのメソッドは、deriveContainsに対して生成されます。
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
最初はあまり多くの要素を挿入していませんが、フォークして自由に変更できるため、これは実際のベンチマークではありません。
少し「ハッキー」と考えられるかもしれませんが、スライスのサイズと内容によっては、スライスを結合して文字列検索を実行できます。
たとえば、単一の単語値を含むスライスがあります(たとえば、「yes」、「no」、「maybe」)。これらの結果はスライスに追加されます。このスライスに「たぶん」結果が含まれているかどうかを確認したい場合は、
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
これがどれほど適切であるかは、スライスのサイズとそのメンバーの長さに依存します。大きなスライスや長い値にはパフォーマンスや適合性の問題があるかもしれませんが、有限サイズで単純な値の小さなスライスの場合、目的の結果を得るには有効な1行です。
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"
})