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.
Pamiętaj również, że musisz napisać, 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).
tux21b
5
Rozwiązanie jest proste, to prawda. Ale co trzeba, aby dodać taką podstawową funkcjonalność do środowiska wykonawczego? Nie znalazłem takich problemów w repozytorium Go na github. To smutne i dziwne.
Igor Pietrow
1
Jak wypada map[string] boolporównanie map[string] struct{}. map[string] struct{}wygląda na włamanie szczególnie inicjujące pustą strukturęstruct {}{}
vadasambar
@IgorPetrov zgodził się, jestem zaskoczony, że tak podstawowej funkcji nie ma już w środowisku uruchomieniowym.
jcollum
180
Nie, taka metoda nie istnieje, ale napisanie jej jest trywialne:
func contains(s []int, e int)bool{for _, a := range s {if a == e {returntrue}}returnfalse}
Możesz użyć mapy, jeśli to wyszukiwanie jest ważną częścią twojego kodu, ale mapy też mają swoje koszty.
W rzeczywistości nie jest to trywialne, ponieważ musisz napisać po jednym dla każdego używanego typu, a ponieważ nie ma przeciążenia, musisz nazwać każdą funkcję inaczej, tak jak w C. append () może działać ogólnie, ponieważ ma specjalne wsparcie środowiska wykonawczego. Ogólny zawiera byłby użyteczny z tego samego powodu, ale tak naprawdę ogólnym rozwiązaniem jest po prostu ogólne wsparcie w języku.
Eloff,
15
@Eloffinterface{}
Alex Lockwood
2
@Alex Lockwood czy to faktycznie będzie działać z interfejsami?
Ory Band
101
trywialny == 7 linii kodu, w tym 1 pętla 1 gałąź if instrukcja i 1 porównanie? Myślę, że coś mi tu brakuje ...
tothemario,
3
Ale dlaczego nie dodać tych samych elementów do samego rdzenia?
Luna Lovegood
16
Jeżeli plaster jest posortowana, jest binarny wyszukiwania realizowane w tym sortpakiecie .
Zamiast używać slice, mapmoż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))}
W obecnej formie ten kod nie przynosi żadnych korzyści, ponieważ nie ma sensu budować mapy z wycinka, jeśli zamierzasz go użyć tylko raz. - Aby był przydatny, ten kod powinien raczej zapewniać funkcję, sliceToMapktóra wykonuje wszystkie przygotowania. Następnie wyszukiwanie mapy jest banalne i wydajne.
Roland Illig,
9
Rodzaj pakiet zawiera budulcem jeśli plaster jest posortowana czy jesteś gotów go uporządkować.
SearchStringzapowiada 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.
Jeśli chodzi o czas, regularne wyszukiwanie jest możliwe O(n)i dzięki temu rozwiązaniu O(n*log(n)).
plesiv
@plesiv to wyszukiwanie binarne, AFAICS. Czy to nie oznaczałoby, że O (log n)?
Henrik Aasted Sørensen
tak, wyszukiwanie binarne i funkcja containssą O(log(n)), ale ogólne podejście O(n*log(n))wynika z tego rodzaju.
plesiv
3
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.Interfaceif arrV.Index(i).Interface()== elem {returntrue}}}returnfalse}
Jasne, że możesz użyć pakietu odbicia, ale tylko dlatego, że możesz, nie oznacza to, że powinieneś. Odbicie jest bardzo drogie.
Justin Ohms
3
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 Foostruct{Field1stringField2int}
func Test(m Foo)bool{var allItems []Fooreturn deriveContainsFoo(allItems, m)}
Aby wygenerować metodę deriveContainsFoo:
Zainstaluj goderive za pomocą go get -u github.com/awalterschulze/goderive
Uruchom goderive ./...w folderze obszaru roboczego
Ta metoda zostanie wygenerowana dla DeriveContains:
func deriveContainsFoo(list []Foo, item Foo)bool{for _, v := range list {if v == item {returntrue}}returnfalse}
Goderive obsługuje wiele innych przydatnych metod pomocniczych, pozwalających na zastosowanie funkcjonalnego stylu programowania.
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 Identifiableinterface{GetIdentity()string}
func IsIdentical(thisIdentifiable, that Identifiable)bool{return(&this==&that)||(this.GetIdentity()== that.GetIdentity())}
func contains(s []Identifiable, e Identifiable)bool{for _, a := range s {ifIsIdentical(a,e){returntrue}}returnfalse}
„nie jest niczym więcej niż to, co musiałbyś robić w innych językach” nie jest tak naprawdę prawdą - np. w C # Contains()jest zaimplementowany List<T>, więc musisz tylko zaimplementować Equals()tę pracę.
George
1
Stworzyłem bardzo prosty test porównawczy z rozwiązaniami z tych odpowiedzi.
Myślałem o tym, ale nie jest tak reprezentatywny, ponieważ moja maszyna nie jest tak potężna.
F. Norbert
0
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.
Nie będzie działać w sytuacji, gdy elementy mają podobny tekst, ale nie dokładnie taki samexSlice := ["yes and no", "maybe", "maybe another"]
Raees Iqbal
Jest to dość przyjemne podejście do uzyskania szybkiego i brudnego rozwiązania z jedną linią. Musisz tylko wymagać jednoznacznego separatora (może być przecinkiem) i wykonać dodatkową pracę, aby ","+strings.Join(exSlice,",")+","",maybe,"
spakować
-1
Styl Go:
func Contains(n int, match func(i int)bool)bool{for i :=0; i < n; i++{if match(i){returntrue}}returnfalse}
s :=[]string{"a","b","c","o"}// test if s contains "o"
ok :=Contains(len(s), func(i int)bool{return s[i]=="o"})
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 pustegostruct{}
miejsca ma tę zaletę, że nie wymaga dodatkowej przestrzeni, a wewnętrzny typ mapy Go jest zoptymalizowany dla tego rodzaju wartości. Dlategomap[string] struct{}
jest popularnym wyborem dla zestawów w świecie Go.źródło
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ównaniemap[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:
Możesz użyć mapy, jeśli to wyszukiwanie jest ważną częścią twojego kodu, ale mapy też mają swoje koszty.
źródło
interface{}
Jeżeli plaster jest posortowana, jest binarny wyszukiwania realizowane w tym
sort
pakiecie .źródło
Zamiast używać
slice
,map
może być lepszym rozwiązaniem.prosty przykład:
http://play.golang.org/p/CEG6cu4JTf
źródło
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ć.
SearchString
zapowiada powrótthe 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.źródło
O(n)
i dzięki temu rozwiązaniuO(n*log(n))
.contains
sąO(log(n))
, ale ogólne podejścieO(n*log(n))
wynika z tego rodzaju.Możesz użyć pakietu odbicia do iteracji po interfejsie, którego konkretnym typem jest plasterek:
https://play.golang.org/p/jL5UD7yCNq
źródło
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;
Aby wygenerować metodę deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
w folderze obszaru roboczegoTa metoda zostanie wygenerowana dla DeriveContains:
Goderive obsługuje wiele innych przydatnych metod pomocniczych, pozwalających na zastosowanie funkcjonalnego stylu programowania.
źródło
źródło
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 ().
źródło
Contains()
jest zaimplementowanyList<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ć.
źródło
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ć
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.
źródło
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
Styl Go:
źródło