wake-up-neo.net

Enthält die Methode für ein Slice

Gibt es etwas Ähnliches wie eine slice.contains(object) -Methode in Go, ohne jedes Element in einem Slice durchsuchen zu müssen?

152
vosmith

Mostafa hat bereits darauf hingewiesen, dass eine solche Methode trivial zu schreiben ist, und mkb gab Ihnen einen Hinweis, die binäre Suche aus dem Sortierpaket zu verwenden. Wenn Sie jedoch viele solcher Prüfungen durchführen, können Sie auch eine Karte verwenden.

Es ist ganz einfach zu überprüfen, ob ein bestimmter Kartenschlüssel vorhanden ist, indem Sie die IDiom value, ok := yourmap[key] Verwenden. Da Sie sich nicht für den Wert interessieren, können Sie beispielsweise auch einen map[string]struct{} Erstellen. Die Verwendung eines leeren struct{} Hat den Vorteil, dass kein zusätzlicher Speicherplatz benötigt wird und der interne Kartentyp von Go für diese Art von Werten optimiert ist. Daher ist map[string] struct{} Eine beliebte Wahl für Sets in der Go-Welt.

190
tux21b

Nein, eine solche Methode gibt es nicht, aber es ist trivial zu schreiben:

func contains(s []int, e int) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

Sie können eine Karte verwenden, wenn diese Suche ein wichtiger Bestandteil Ihres Codes ist, aber auch Kosten verursacht.

142
Mostafa

Wenn das Segment sortiert ist, ist eine binäre Suche in dem sort -Paket implementiert.

13
mkb

Anstelle eines slice könnte map eine bessere Lösung sein.

einfaches Beispiel:

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

8
holys

Sie können das Paket reflect verwenden, um über eine Schnittstelle zu iterieren, deren konkreter Typ ein Slice ist:

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

5
Ethan Kennedy

Nicht sicher, ob Generika hier benötigt werden. Sie brauchen nur einen Vertrag für Ihr gewünschtes Verhalten. Das Folgende ist nicht mehr als das, was Sie in anderen Sprachen tun müssten, wenn Sie möchten, dass sich Ihre eigenen Objekte in Auflistungen verhalten, indem Sie beispielsweise Equals () und GetHashCode () überschreiben.

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
}
3
JonPen

Wenn es nicht möglich ist, eine Karte zum Auffinden von Objekten auf der Grundlage eines Schlüssels zu verwenden, können Sie das goderive -Tool in Betracht ziehen. Goderive generiert eine typspezifische Implementierung einer contain-Methode, wodurch Ihr Code sowohl lesbar als auch effizient wird.

Beispiel;

type Foo struct {
    Field1 string
    Field2 int
} 

func Test(m Foo) bool {
     var allItems []Foo
     return deriveContainsFoo(allItems, m)
}

So generieren Sie die deriveContainsFoo-Methode:

  • Installiere goderive mit go get -u github.com/awalterschulze/goderive
  • Lauf goderive ./... in Ihrem Arbeitsbereichsordner

Diese Methode wird für deniveContains generiert:

func deriveContainsFoo(list []Foo, item Foo) bool {
    for _, v := range list {
        if v == item {
            return true
        }
    }
    return false
}

Goderive bietet Unterstützung für eine Reihe weiterer nützlicher Hilfsmethoden, um unterwegs einen funktionalen Programmierstil anzuwenden.

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
Jim Hsiang