Yanıtlar:
Mostafa zaten böyle bir yöntemin yazmak için önemsiz olduğunu belirtti ve mkb size sıralama paketinden ikili aramayı kullanmanız için bir ipucu verdi. Ancak, bu tür birçok kontroller yapacaksanız, bunun yerine bir harita kullanmayı da düşünebilirsiniz.
Deyimi kullanarak belirli bir harita anahtarının mevcut olup olmadığını kontrol etmek önemsizdir value, ok := yourmap[key]
. Değerle ilgilenmediğiniz map[string]struct{}
için, örneğin bir tane de oluşturabilirsiniz . struct{}
Burada boş bir alan kullanmanın ek alan gerektirmemesi ve Go'nun dahili harita türünün bu tür değerler için optimize edilmesi avantajı vardır. Bu nedenle, map[string] struct{}
Go dünyasındaki setler için popüler bir seçimdir.
struct{}{}
bir öğe eklemek istediğinizde haritanıza aktarabilmeniz için boş yapının değerini almak için yazmanız gerektiğini unutmayın . Sadece deneyin ve herhangi bir sorunla karşılaşırsanız sormaya çekinmeyin. Eğer daha kolay anlaşılırsa (büyük miktarda veriye sahip değilseniz) Mostafa'nın çözümünü de kullanabilirsiniz.
map[string] bool
karşılaştırılır map[string] struct{}
. map[string] struct{}
özellikle boş bir yapı struct {}{}
Hayır, böyle bir yöntem mevcut değildir, ancak yazmak önemsizdir:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Bu arama kodunuzun önemli bir parçasıysa, ancak haritaların da maliyeti varsa bir harita kullanabilirsiniz.
interface{}
Yerine a kullanmanın slice
, map
daha iyi bir çözüm olabilir.
basit bir örnek:
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
tüm hazırlıkları yapan bir işlev sağlamalıdır . Bundan sonra haritayı sorgulamak önemsiz ve etkilidir.
Sıralama senin dilim sıralı veya bunu sıralamak için istekli olup olmadığını paketi bina blokları sağlar.
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
geri dönmeyi vaat eder the index to insert x if x is not present (it could be len(a))
, bu nedenle bir kontrol dizenin sıralanan dilimi içerip içermediğini gösterir.
O(n)
ve bu çözüm bunu yapar O(n*log(n))
.
contains
vardır O(log(n))
, ancak genel yaklaşım O(n*log(n))
sıralamaya bağlıdır.
Yansıtma paketini, beton türü bir dilim olan bir arabirim üzerinde yinelemek için kullanabilirsiniz :
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
}
Bir anahtara dayalı öğeleri bulmak için bir harita kullanmak mümkün değilse, goderive aracını düşünebilirsiniz . Goderive, içerme yönteminin türe özgü bir uygulamasını oluşturur ve kodunuzu hem okunabilir hem de verimli hale getirir.
Misal;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
DeriveContainsFoo yöntemini oluşturmak için:
go get -u github.com/awalterschulze/goderive
goderive ./...
alanı klasörünüzde çalıştırınBu yöntem deriveContains için oluşturulacaktır:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive, işlevsel bir programlama stili uygulamak için diğer bazı yararlı yardımcı yöntemleri destekliyor.
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
}
Burada jeneriklerin gerekli olduğundan emin değilim. İstediğiniz davranış için bir sözleşmeye ihtiyacınız var. Aşağıdakileri yapmak, örneğin Equals () ve GetHashCode () öğelerini geçersiz kılarak kendi nesnelerinizin koleksiyonlarda kendilerini hareket etmesini istiyorsanız, diğer dillerde yapmanız gerekenden daha fazlası değildir.
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()
uygulandığını List<T>
yalnızca hiç uygulamak zorunda, Equals()
o iş için.
Bu cevapların çözümleriyle çok basit bir karşılaştırma ölçütü oluşturdum.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Bu gerçek bir kriter değil çünkü başlangıçta çok fazla eleman eklemedim ama çatallanıp değiştirmekten çekinmeyin.
Biraz 'hacky' olarak kabul edilebilir, ancak dilimin boyutuna ve içeriğine bağlı olarak, dilime birlikte katılabilir ve bir dize araması yapabilirsiniz.
Örneğin, tek kelime değerleri içeren bir diliminiz var (örneğin, "evet", "hayır", "belki"). Bu sonuçlar bir dilime eklenir. Bu dilimin herhangi bir "belki" sonucu içerip içermediğini kontrol etmek istiyorsanız,
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
Bunun ne kadar uygun olduğu gerçekten dilimin büyüklüğüne ve üyelerinin uzunluğuna bağlıdır. Büyük dilimler veya uzun değerler için performans veya uygunluk sorunları olabilir, ancak daha küçük sonlu boyutlu dilimler ve basit değerler için, istenen sonucu elde etmek için geçerli bir astardır.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
ve",maybe,"
Git tarzı:
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"
})