423 Stimmen

Erhalten eines Schlüsselausschnitts aus einer Karte

Gibt es einen einfacheren/schöneren Weg, um in Go einen Ausschnitt von Schlüsseln aus einer Map zu bekommen?

Derzeit iteriere ich über die Map und kopiere die Schlüssel in einen Slice:

i := 0
keys := make([]int, len(mymap))
for k := range mymap {
    keys[i] = k
    i++
}

559voto

Vinay Pai Punkte 6824

Das ist eine alte Frage, aber hier sind meine Gedanken dazu. Die Antwort von PeterSO ist etwas prägnanter, aber etwas weniger effizient. Sie wissen bereits, wie groß es sein wird, also müssen Sie nicht einmal append verwenden:

keys := make([]int, len(mymap))

i := 0
for k := range mymap {
    keys[i] = k
    i++
}

In den meisten Situationen wird es wahrscheinlich keinen großen Unterschied machen, aber es ist nicht viel mehr Arbeit, und in meinen Tests (Verwendung einer Karte mit 1.000.000 zufälligen int64 Schlüsseln und dann zehnmal das Array der Schlüssel mit jeder Methode zu generieren) war es ungefähr 20% schneller, die Elemente des Arrays direkt zuzuweisen als append zu verwenden.

Auch wenn die Festlegung der Kapazität Neuzuweisungen vermeidet, muss append immer noch zusätzliche Arbeit leisten, um zu überprüfen, ob Sie die Kapazität bei jedem append erreicht haben.

307voto

peterSO Punkte 146133

Zum Beispiel,

package main

func main() {
    mymap := make(map[int]string)
    keys := make([]int, 0, len(mymap))
    for k := range mymap {
        keys = append(keys, k)
    }
}

Um in Go effizient zu sein, ist es wichtig, Speicherzuweisungen zu minimieren.

125voto

Denis Kreshikhin Punkte 7906

Sie können auch ein Array von Schlüsseln mit dem Typ []Value mit der Methode MapKeys der Struktur Value aus dem Paket "reflect" erhalten:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    abc := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }

    keys := reflect.ValueOf(abc).MapKeys()

    fmt.Println(keys) // [a b c]
}

97voto

blackgreen Punkte 23721

Go hat jetzt Generics. Du kannst die Schlüssel einer beliebigen Map mit maps.Keys erhalten.

Beispiel Verwendung:

    intMap := map[int]int{1: 1, 2: 2}
    intKeys := maps.Keys(intMap)
    // intKeys ist []int
    fmt.Println(intKeys)

    strMap := map[string]int{"alpha": 1, "bravo": 2}
    strKeys := maps.Keys(strMap)
    // strKeys ist []string
    fmt.Println(strKeys)

maps Package befindet sich in golang.org/x/exp/maps. Dies ist experimentell und außerhalb der Go-Kompatibilitätsgarantie. Sie haben vor, es in die std-Lib in Go 1.19 Zukunft zu verschieben.

Playground: https://go.dev/play/p/fkm9PrJYTly

Für diejenigen, die keine exp-Pakete importieren möchten, hier ist der Quellcode (ursprünglich verfasst von Ian Lance Taylor), der wie Sie sehen können sehr einfach ist:

// Keys gibt die Schlüssel der Map m zurück.
// Die Schlüssel werden in einer unbestimmten Reihenfolge sein.
func Keys[M ~map[K]V, K comparable, V any](m M) []K {
    r := make([]K, 0, len(m))
    for k := range m {
        r = append(r, k)
    }
    return r
}

HINWEIS: In Go 1.21 wurde ein Teil des maps Pakets in die Standardbibliothek verschoben, aber nicht maps.Keys. Für Details siehe das Go-Issue maps: remove Keys and Values for Go 1.21 tl;dr die Keys Methode könnte eine andere Signatur haben. Daher sind die hier vorgestellten Lösungen (Verwendung von x/exp/maps oder Kopieren des Quellcodes) auch in Go 1.21 anwendbar.

24voto

Nico Villanueva Punkte 786

Ich habe einen groben Benchmark zu den drei in anderen Antworten beschriebenen Methoden erstellt.

Offensichtlich ist das Vorab-Allozieren des Slices vor dem Abrufen der Schlüssel schneller als append, aber überraschenderweise ist die reflect.ValueOf(m).MapKeys()-Methode signifikant langsamer als Letzteres:

 go run scratch.go
populating
filling 100000000 slots
done in 56.630774791s
running prealloc
took: 9.989049786s
running append
took: 18.948676741s
running reflect
took: 25.50070649s

Hier ist der Code: https://play.golang.org/p/Z8O6a2jyfTH (wenn Sie ihn im Playground ausführen, bricht er ab und behauptet, dass es zu lange dauert, also führen Sie ihn lokal aus.)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X