Risposte:
Mostafa ha già sottolineato che un tale metodo è banale da scrivere, e mkb ti ha dato un suggerimento per usare la ricerca binaria dal pacchetto di ordinamento. Ma se hai intenzione di fare molti di questi controlli, potresti anche considerare di usare una mappa.
È banale verificare se esiste una chiave della mappa specifica usando il value, ok := yourmap[key]
linguaggio. Dal momento che non sei interessato al valore, potresti anche creare un map[string]struct{}
esempio. L'uso di uno struct{}
spazio vuoto qui ha il vantaggio di non richiedere spazio aggiuntivo e il tipo di mappa interna di Go è ottimizzato per quel tipo di valori. Pertanto, map[string] struct{}
è una scelta popolare per i set nel mondo Go.
struct{}{}
per ottenere il valore della struttura vuota in modo da poterlo passare alla mappa quando si desidera aggiungere un elemento. Provalo e, se riscontri problemi, non esitare a chiedere. Puoi anche usare la soluzione di Mostafa se è più facile da capire (a meno che tu non abbia enormi quantità di dati).
map[string] bool
confronta con map[string] struct{}
. map[string] struct{}
sembra un trucco soprattutto inizializzando una struttura vuotastruct {}{}
No, tale metodo non esiste, ma è banale scrivere:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Puoi usare una mappa se quella ricerca è una parte importante del tuo codice, ma anche le mappe hanno un costo.
interface{}
Se la fetta è ordinato, v'è una ricerca binaria implementato nel sort
pacchetto .
Invece di usare a slice
, map
potrebbe essere una soluzione migliore.
semplice esempio:
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
che faccia tutta la preparazione. Dopodiché, interrogare la mappa è banale ed efficiente.
Il pacchetto di ordinamento fornisce gli elementi costitutivi se la sezione è ordinata o se si è disposti a ordinarla.
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
promette di tornare the index to insert x if x is not present (it could be len(a))
, quindi un controllo di ciò rivela se la stringa è contenuta la sezione ordinata.
O(n)
e questa soluzione lo rende O(n*log(n))
.
contains
sono O(log(n))
, ma l'approccio generale è O(n*log(n))
dovuto all'ordinamento.
È possibile utilizzare il pacchetto riflesso per scorrere su un'interfaccia il cui tipo concreto è una sezione:
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
}
Se non è possibile utilizzare una mappa per trovare oggetti in base a una chiave, puoi prendere in considerazione lo strumento goderive . Goderive genera un'implementazione specifica per tipo di un metodo contiene, rendendo il codice leggibile ed efficiente.
Esempio;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Per generare il metodo deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
nella cartella dell'area di lavoroQuesto metodo verrà generato per deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive supporta alcuni altri utili metodi di supporto per applicare uno stile di programmazione funzionale in atto.
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
}
Non sono sicuro che i farmaci generici siano necessari qui. Hai solo bisogno di un contratto per il tuo comportamento desiderato. Fare quanto segue non è altro che quello che dovresti fare in altre lingue se volessi che i tuoi oggetti si comportassero nelle raccolte, sostituendo Equals () e GetHashCode () per esempio.
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()
è implementato List<T>
, quindi devi solo implementarlo Equals()
per quel lavoro.
Ho creato un benchmark molto semplice con le soluzioni da queste risposte.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Non è un vero punto di riferimento perché inizialmente non ho inserito troppi elementi ma mi sento libero di biforcarlo e cambiarlo.
Potrebbe essere considerato un po '"confuso", ma a seconda delle dimensioni e del contenuto della sezione, puoi unire la sezione e fare una ricerca di stringhe.
Ad esempio, hai una sezione contenente valori di una sola parola (ad es. "Sì", "no", "forse"). Questi risultati vengono aggiunti a una sezione. Se si desidera verificare se questa sezione contiene risultati "forse", è possibile utilizzare
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
Quanto sia adatto dipende davvero dalle dimensioni della sezione e dalla lunghezza dei suoi membri. Potrebbero esserci problemi di prestazioni o idoneità per sezioni grandi o valori lunghi, ma per sezioni più piccole di dimensioni finite e valori semplici è un liner valido per ottenere il risultato desiderato.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"
Lo stile 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"
})