110 votes

Comment itérer à travers une carte en Golang dans l'ordre?

Veuillez trouver ci-dessous ma carte

var romanNumeralDict map[int]string = map[int]string{
  1000: "M",
  900 : "CM",
  500 : "D",
  400 : "CD",
  100 : "C",
  90  : "XC",
  50  : "L",
  40  : "XL",
  10  : "X",
  9   : "IX",
  5   : "V",
  4   : "IV",
  1   : "I",
}

Je cherche à parcourir cette carte dans l'ordre de la taille de la clé

  for k, v := range romanNumeralDict {
    fmt.Println("k:", k, "v:", v)
  }

Cependant, cela affiche

k: 1000 v: M
k: 40 v: XL
k: 5 v: V
k: 4 v: IV
k: 900 v: CM
k: 500 v: D
k: 400 v: CD
k: 100 v: C
k: 90 v: XC
k: 50 v: L
k: 10 v: X
k: 9 v: IX
k: 1 v: I

Y a-t-il un moyen de les afficher dans l'ordre de la taille de la clé, donc j'aimerais boucler à travers cette carte de cette manière

k:1
K:4
K:5
K:9
k:10

etc...

155voto

Volker Points 6807

Collectez toutes les clés, triez-les et itérez votre map par clé, comme suit :

keys := make([]int, 0)
for k, _ := range romanNumeralDict {
    keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
    fmt.Println(k, romanNumeralDict[k])
}

47voto

Timmmm Points 9909

Vous pouvez rendre cela un peu plus rapide en préallouant keys car vous connaissez sa longueur:

func sortedKeys(m map[Key]Value) ([]Key) {
        keys := make([]Key, len(m))
        i := 0
        for k := range m {
            keys[i] = k
            i++
        }
        sort.Keys(keys)
        return keys
}

Remplacez Key et Value par vos types de clé et de valeur (y compris la ligne sort). toux génériques toux

Modifier : Go 1.18 obtient enfin des génériques ! Voici la version générique:

// Ordered est une contrainte de type qui correspond à n'importe quel type ordonné.
// Un type ordonné est un type qui prend en charge les opérateurs <, <=, >, et >=.
//
// Notez que la proposition de génériques suggère que ce type sera disponible à partir
// d'un futur package "constraints" standard.
type Ordered interface {
    type int, int8, int16, int32, int64,
        uint, uint8, uint16, uint32, uint64, uintptr,
        float32, float64,
        string
}

func sortedKeys[K Ordered, V any](m map[K]V) ([]K) {
        keys := make([]K, len(m))
        i := 0
        for k := range m {
            keys[i] = k
            i++
        }
        sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
        return keys
}

Modifier 2 : Go 1.21 L'interface Ordered ci-dessus peut être remplacée par cmp.Ordered

Exemple de playground

4voto

nobar Points 5849

Vous pouvez obtenir un tableau triable de clés en utilisant MapKeys.

Dans cet exemple, les clés sont de type string:

keys := reflect.ValueOf(myMap).MapKeys()
keysOrder := func(i, j int) bool { return keys[i].Interface().(string) < keys[j].Interface().(string) }
sort.Slice(keys, keysOrder)

// traiter la carte dans l'ordre trié des clés
for _, key := range keys {
    value := myMap[key.Interface().(string)]
    fmt.Println(key, value)
}
  • Voir : Obtenir une tranche de clés à partir d'une carte
  • Avertissement : Cela contourne certaines vérifications de type à la compilation (panique si ce n'est pas une carte)
  • Vous devrez caster chaque clé pour obtenir sa valeur brute : key.Interface().(string)

1voto

Sarath Kumar Sivan Points 2095

Vous pouvez itérer sur la carte dans l'ordre en triant d'abord explicitement les clés, puis itérer sur la carte par clé. Comme vous connaissez la taille finale des clés depuis le début romanNumeralDict, il est plus efficace d'allouer un tableau de la taille requise à l'avance.

// Slice pour spécifier l'ordre de la carte.
// Il est initialement vide mais a une capacité suffisante
// pour contenir toutes les clés de la carte romanNumeralDict.
clés := make([]int, 0, len(romanNumeralDict))

// Collecter les clés de la carte
i := 0
for k, _ := range romanNumeralDict {
    clés[i] = k
    i++
}

// Ints trie une tranche d'entiers par ordre croissant
sort.Ints(clés)

// Itérer sur la carte par clé avec un ordre
for _, k := range clés {
    fmt.Println(k, romanNumeralDict[k])
}

1voto

Howl Points 1138

Basé sur la réponse de @Brent, j'ai eu une occasion où je voulais des clés de map triées dans un morceau de code non critique, sans avoir à me répéter trop. Voici donc un point de départ pour créer une fonction d'itération de map générique pour de nombreux types différents :

func sortedMapIteration(m interface{}, f interface{}) {
    // obtenir la valeur et les clés
    val := reflect.ValueOf(m)
    keys := val.MapKeys()
    var sortFunc func(i, j int) bool
    kTyp := val.Type().Key()

    // déterminer quelle fonction de tri utiliser pour les clés en fonction de leurs types.
    switch {
    case kTyp.Kind() == reflect.Int:
        sortFunc = func(i, j int) bool { return keys[i].Int() < keys[j].Int() }
    case kTyp.Kind() == reflect.String:
        sortFunc = func(i, j int) bool { return keys[i].String() < keys[j].String() }
    }
    sort.Slice(keys, sortFunc)

    // obtenir la fonction et l'appeler pour chaque clé.
    fVal := reflect.ValueOf(f)
    for _, key := range keys {
        value := val.MapIndex(key)
        fVal.Call([]reflect.Value{key, value})
    }
}

// exemple :
func main() {
    sortedMapIteration(map[string]int{
        "009": 9,
        "003": 3,
        "910": 910,
    }, func(s string, v int) {
        fmt.Println(s, v)
    })
}

<a href="https://go.dev/play/p/edXaWpIBDNh" rel="nofollow noreferrer">terrain de jeu</a>

Pour insister : ce code est inefficace et utilise la réflexion, il n'a donc pas de sécurité de type au moment de la compilation, et une implémentation générique devrait avoir davantage de protections de type et gérer davantage de types de clés. Cependant, pour des scripts rapides et peu soignés, cela peut vous aider à démarrer. Vous devrez ajouter plus de cas au bloc switch, en fonction des types de clés que vous prévoyez de passer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X