Contiene il metodo per una sezione


Risposte:


226

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.


27
Si noti inoltre che è necessario scrivere 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).
tux21b,

5
La soluzione è semplice, è vero. Ma cosa serve per aggiungere tali funzionalità di base nel runtime? Non ho riscontrato tali problemi nel repository Go su github. È triste e strano.
Igor Petrov,

1
Come si map[string] boolconfronta con map[string] struct{}. map[string] struct{}sembra un trucco soprattutto inizializzando una struttura vuotastruct {}{}
vadasambar

@IgorPetrov ha concordato, sono sorpreso che una funzionalità di base non sia già in fase di esecuzione.
jcollum,

180

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.


257
In realtà non è banale, perché devi scriverne uno per ogni tipo che usi, e poiché non c'è sovraccarico, devi nominare ciascuna funzione in modo diverso, come in C. append () può funzionare genericamente perché ha uno speciale supporto di runtime. Un generico contiene sarebbe utile per lo stesso motivo, ma in realtà la soluzione generica è solo il supporto generici nella lingua.
Eloff,

15
@Eloffinterface{}
Alex Lockwood,

2
@Alex Lockwood funzionerà effettivamente con le interfacce?
Ory Band

101
banale == 7 righe di codice incluso 1 ramo 1 ciclo se istruzione e 1 confronto? Penso che mi manchi qualcosa qui ...
tothemario,

3
Ma perché non aggiungerli in go core stesso?
Luna Lovegood,


12

Invece di usare a slice, mappotrebbe 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))

}

http://play.golang.org/p/CEG6cu4JTf


34
Nella sua forma attuale questo codice non offre alcun vantaggio, dal momento che non ha senso costruire una mappa da una sezione se la userete solo una volta. - Per essere utile, questo codice dovrebbe piuttosto fornire una funzione sliceToMapche faccia tutta la preparazione. Dopodiché, interrogare la mappa è banale ed efficiente.
Roland Illig,

9

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
}

SearchStringpromette 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.


In termini di tempo, la ricerca regolare è O(n)e questa soluzione lo rende O(n*log(n)).
plesiv

@plesiv è una ricerca binaria, AFAICS. Non lo farebbe O (log n)?
Henrik Aasted Sørensen

sì, la ricerca binaria e la funzione lo containssono O(log(n)), ma l'approccio generale è O(n*log(n))dovuto all'ordinamento.
plesiv

3

È 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
}

https://play.golang.org/p/jL5UD7yCNq


3
Sicuramente puoi usare il pacchetto reflection, ma solo perché puoi, non significa che dovresti. La riflessione è molto costosa.
Justin Ohms,

3

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:

  • Installa goderive con go get -u github.com/awalterschulze/goderive
  • Esegui goderive ./...nella cartella dell'area di lavoro

Questo 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.


2
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
}

2

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
}

1
"non è altro che ciò che dovresti fare in altre lingue" non è proprio vero, ad esempio in C # Contains()è implementato List<T>, quindi devi solo implementarlo Equals()per quel lavoro.
George,


0

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.


Non funzionerà per situazioni in cui elementi hanno un testo simile ma non esattamente lo stessoexSlice := ["yes and no", "maybe", "maybe another"]
Raees Iqbal

Questo è un approccio piuttosto piacevole per ottenere una soluzione one-liner veloce e sporca. Devi solo richiedere un delimitatore inequivocabile (potrebbe essere una virgola) e fare il lavoro extra per racchiudere entrambe le stringhe ","+strings.Join(exSlice,",")+","",maybe,"
:,

-1

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"
})

2
Questo non risponde alla domanda, né fornisce informazioni aggiuntive.
Croolman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.