So suchen Sie nach einem Element in einem Golang-Slice

73

Ich habe ein Stück Strukturen.

type Config struct {
    Key string
    Value string
}

// I form a slice of the above struct
var myconfig []Config 

// unmarshal a response body into the above slice
if err := json.Unmarshal(respbody, &myconfig); err != nil {
    panic(err)
}

fmt.Println(config)

Hier ist die Ausgabe davon:

[{key1 test} {web/key1 test2}]

Wie kann ich dieses Array durchsuchen, um das Element wo zu erhalten key="key1"?

Codec
quelle
Da Ihre Konfigurationsstruktur wie eine einfache Zuordnung aussieht, möchte ich darauf hinweisen, dass Sie alle JSON-Daten in a dekodieren können map[string]interface{}. Wenn Sie interessiert sind,
überprüfen

Antworten:

123

Mit einer einfachen forSchleife:

for _, v := range myconfig {
    if v.Key == "key1" {
        // Found!
    }
}

Da der Elementtyp des Slice ein struct(kein Zeiger) ist, kann dies ineffizient sein, wenn der Strukturtyp "groß" ist, da die Schleife jedes besuchte Element in die Schleifenvariable kopiert.

Es wäre schneller, eine rangeSchleife nur für den Index zu verwenden. Dadurch wird vermieden, dass die Elemente kopiert werden:

for i := range myconfig {
    if myconfig[i].Key == "key1" {
        // Found!
    }
}

Anmerkungen:

Es hängt von Ihrem Fall ab, ob mehrere Konfigurationen mit derselben vorhanden keysind. Wenn nicht, sollten Sie breakdie Schleife verlassen, wenn eine Übereinstimmung gefunden wird (um die Suche nach anderen zu vermeiden).

for i := range myconfig {
    if myconfig[i].Key == "key1" {
        // Found!
        break
    }
}

Auch wenn dies eine häufige Operation ist, sollten Sie in Betracht ziehen, daraus eine zu maperstellen, die Sie einfach indizieren können, z

// Build a config map:
confMap := map[string]string{}
for _, v := range myconfig {
    confMap[v.Key] = v.Value
}

// And then to find values by key:
if v, ok := confMap["key1"]; ok {
    // Found
}
icza
quelle
Danke, ich kann auch Zeiger verwenden. Denken Sie, dass die Verwendung eines Zeigers auf struct hier schneller wäre? Können wir eine Reihe von Zeigern haben?
Codec
@ love2code Ja, Sie können auch ein Stück Zeiger verwenden. Wenn Sie die Indizes durchlaufen (wie in meinem zweiten Beispiel), werden die Werte nicht kopiert. Wie du willst.
icza
ok, ich var myconfig []*Confighabe deinen ersten Ansatz erstellt und verwendet. Ich hoffe, dies ist die beste Option
Codec
@ love2code Die beste Option für die Leistung besteht darin, daraus eine Karte zu erstellen, die Sie indizieren können. Siehe bearbeitete Antwort.
icza
19

Sie können sort.Slice()plus verwendensort.Search()

type Person struct {
    Name string
}

func main() {
    crowd := []Person{{"Zoey"}, {"Anna"}, {"Benni"}, {"Chris"}}

    sort.Slice(crowd, func(i, j int) bool {
        return crowd[i].Name <= crowd[j].Name
    })

    needle := "Benni"
    idx := sort.Search(len(crowd), func(i int) bool {
        return string(crowd[i].Name) >= needle
    })

    if crowd[idx].Name == needle {
        fmt.Println("Found:", idx, crowd[idx])
    } else {
        fmt.Println("Found noting: ", idx)
    }
}

Siehe: https://play.golang.org/p/47OPrjKb0g_c

Tarion
quelle
8

Sie können die Struktur in einer Map speichern, indem Sie die Struktur Keyund die ValueKomponenten mit ihren fiktiven Schlüssel- und Wertteilen auf der Map abgleichen :

mapConfig := map[string]string{}
for _, v := range myconfig {
   mapConfig[v.Key] = v.Value
}

Dann können Sie mit der Golang- Komma- OK-Sprache die Schlüsselpräsenz testen:

if v, ok := mapConfig["key1"]; ok {
    fmt.Printf("%s exists", v)
}   
Endre Simo
quelle
3

Dafür gibt es keine Bibliotheksfunktion. Sie müssen selbst codieren.

for _, value := range myconfig {
    if value.Key == "key1" {
        // logic
    }
}

Arbeitscode: https://play.golang.org/p/IJIhYWROP _

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    type Config struct {
        Key   string
        Value string
    }

    var respbody = []byte(`[
        {"Key":"Key1", "Value":"Value1"},
        {"Key":"Key2", "Value":"Value2"}
    ]`)

    var myconfig []Config

    err := json.Unmarshal(respbody, &myconfig)
    if err != nil {
        fmt.Println("error:", err)
    }

    fmt.Printf("%+v\n", myconfig)

    for _, v := range myconfig {
        if v.Key == "Key1" {
            fmt.Println("Value: ", v.Value)
        }
    }

}
Pravin Mishra
quelle
0

Wie andere Leute bereits kommentiert haben, können Sie Ihre eigene Prozedur mit anonymer Funktion schreiben, um dieses Problem zu lösen.

Ich habe zwei Möglichkeiten verwendet, um es zu lösen:

func Find(slice interface{}, f func(value interface{}) bool) int {
    s := reflect.ValueOf(slice)
    if s.Kind() == reflect.Slice {
        for index := 0; index < s.Len(); index++ {
            if f(s.Index(index).Interface()) {
                return index
            }
        }
    }
    return -1
}

Verwendet Beispiel:

type UserInfo struct {
    UserId          int
}

func main() {
    var (
        destinationList []UserInfo
        userId      int = 123
    )
    
    destinationList = append(destinationList, UserInfo { 
        UserId          : 23,
    }) 
    destinationList = append(destinationList, UserInfo { 
        UserId          : 12,
    }) 
    
    idx := Find(destinationList, func(value interface{}) bool {
        return value.(UserInfo).UserId == userId
    })
    
    if idx < 0 {
        fmt.Println("not found")
    } else {
        fmt.Println(idx)    
    }
}

Zweite Methode mit weniger Rechenaufwand:

func Search(length int, f func(index int) bool) int {
    for index := 0; index < length; index++ {
        if f(index) {
            return index
        }
    }
    return -1
}

Verwendet Beispiel:

type UserInfo struct {
    UserId          int
}

func main() {
    var (
        destinationList []UserInfo
        userId      int = 123
    )
    
    destinationList = append(destinationList, UserInfo { 
        UserId          : 23,
    }) 
    destinationList = append(destinationList, UserInfo { 
        UserId          : 123,
    }) 
    
    idx := Search(len(destinationList), func(index int) bool {
        return destinationList[index].UserId == userId
    })
    
    if  idx < 0 {
        fmt.Println("not found")
    } else {
        fmt.Println(idx)    
    }
}
Omotto
quelle