Odpowiedzi:
Mostafa wskazał już, że taka metoda jest trywialna do napisania, a mkb dał ci wskazówkę, jak korzystać z wyszukiwania binarnego z pakietu sortowania. Ale jeśli zamierzasz wykonać wiele takich kontroli, możesz również rozważyć użycie mapy.
Sprawdzanie, czy istnieje określony klucz mapy, jest proste za pomocą value, ok := yourmap[key]
idiomu. Ponieważ nie jesteś zainteresowany tą wartością, możesz również utworzyć map[string]struct{}
na przykład. Korzystanie z pustego struct{}
miejsca ma tę zaletę, że nie wymaga dodatkowej przestrzeni, a wewnętrzny typ mapy Go jest zoptymalizowany dla tego rodzaju wartości. Dlatego map[string] struct{}
jest popularnym wyborem dla zestawów w świecie Go.
struct{}{}
aby uzyskać wartość pustej struktury, abyś mógł przekazać ją do mapy, gdy chcesz dodać element. Po prostu spróbuj, a jeśli napotkasz jakiekolwiek problemy, możesz zapytać. Możesz także skorzystać z rozwiązania Mostafa, jeśli łatwiej to zrozumieć (chyba że masz ogromne ilości danych).
map[string] bool
porównanie map[string] struct{}
. map[string] struct{}
wygląda na włamanie szczególnie inicjujące pustą strukturęstruct {}{}
Nie, taka metoda nie istnieje, ale napisanie jej jest trywialne:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Możesz użyć mapy, jeśli to wyszukiwanie jest ważną częścią twojego kodu, ale mapy też mają swoje koszty.
interface{}
Jeżeli plaster jest posortowana, jest binarny wyszukiwania realizowane w tym sort
pakiecie .
Zamiast używać slice
, map
może być lepszym rozwiązaniem.
prosty przykład:
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
która wykonuje wszystkie przygotowania. Następnie wyszukiwanie mapy jest banalne i wydajne.
Rodzaj pakiet zawiera budulcem jeśli plaster jest posortowana czy jesteś gotów go uporządkować.
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
zapowiada powrót the index to insert x if x is not present (it could be len(a))
, więc sprawdzenie tego ujawnia, czy łańcuch zawiera posortowany plasterek.
O(n)
i dzięki temu rozwiązaniu O(n*log(n))
.
contains
są O(log(n))
, ale ogólne podejście O(n*log(n))
wynika z tego rodzaju.
Możesz użyć pakietu odbicia do iteracji po interfejsie, którego konkretnym typem jest plasterek:
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
}
Jeśli nie można użyć mapy do znalezienia przedmiotów opartych na kluczu, możesz rozważyć narzędzie goderive . Goderive generuje specyficzną dla typu implementację metody zawiera, dzięki czemu kod jest czytelny i wydajny.
Przykład;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Aby wygenerować metodę deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
w folderze obszaru roboczegoTa metoda zostanie wygenerowana dla DeriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive obsługuje wiele innych przydatnych metod pomocniczych, pozwalających na zastosowanie funkcjonalnego stylu programowania.
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
}
Nie jestem pewien, czy potrzebne są tutaj leki generyczne. Potrzebujesz tylko umowy na swoje pożądane zachowanie. Wykonanie następujących czynności jest niczym więcej niż tym, co musiałbyś zrobić w innych językach, jeśli chcesz, aby własne obiekty zachowywały się same w kolekcjach, na przykład poprzez zastąpienie Equals () i 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()
jest zaimplementowany List<T>
, więc musisz tylko zaimplementować Equals()
tę pracę.
Stworzyłem bardzo prosty test porównawczy z rozwiązaniami z tych odpowiedzi.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
To nie jest prawdziwy punkt odniesienia, ponieważ początkowo nie wstawiłem zbyt wielu elementów, ale mogę je rozwidlać i zmieniać.
Może to być uważane za nieco „hacky”, ale w zależności od wielkości i zawartości wycinka możesz połączyć wycinek i przeprowadzić wyszukiwanie łańcuchowe.
Na przykład masz plasterek zawierający wartości pojedynczych słów (np. „Tak”, „nie”, „może”). Te wyniki są dołączane do wycinka. Jeśli chcesz sprawdzić, czy ten plasterek zawiera jakieś wyniki „być może”, możesz użyć
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
To, jak odpowiednie jest to naprawdę, zależy od wielkości plastra i długości jego elementów. Mogą występować problemy z wydajnością lub przydatnością w przypadku dużych wycinków lub długich wartości, ale w przypadku mniejszych wycinków o skończonych rozmiarach i prostych wartościach można uzyskać pożądany wynik tylko w jednym wierszu.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
Styl Go:
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"
})