web-dev-qa-db-fra.com

Obtenir une clé / un élément arbitraire à partir d'une carte

Je suis nouveau sur Go et maintenant je veux obtenir un élément arbitraire d'une carte; quelle est la façon idiomatique de le faire? Je ne peux penser qu'à quelque chose comme ça:

func get_some_key(m map[int]int) int {
    for k := range m {
        return k
    }
    return 0
}

La raison pour laquelle je le souhaite est que j'utilise une carte pour gérer un ensemble de travaux, et avec une carte, je peux obtenir un travail en attente ou supprimer un travail terminé dans O (1). Je suppose que cela devrait être une exigence courante, mais il n'est pas évident de savoir comment le faire dans Go.

35
chuchao333

La question de savoir si l'obtention d'une clé arbitraire à partir d'une table de hachage est une exigence courante. D'autres implémentations de mappage de langage manquent souvent de cette fonctionnalité (par exemple Dictionnaire en C # )

Cependant, votre solution est probablement la plus rapide, mais il vous restera un algorithme pseudo-aléatoire que vous ne contrôlez pas. Et bien que l'implémentation actuelle utilise un algorithme pseudo-aléatoire, le Go Specification ne vous donne aucune assurance qu'il sera réellement aléatoire, mais seulement qu'il n'est pas garanti d'être prévisible:

L'ordre d'itération sur les cartes n'est pas spécifié et n'est pas garanti d'être le même d'une itération à la suivante.

Si vous voulez plus de contrôle sur la randomisation, vous pouvez également garder en parallèle une tranche mise à jour des valeurs (ou clés) contenues dans la carte, en utilisant la randomisation de votre choix (math/Rand ou crypto/Rand pour les cas les plus extrêmes) pour obtenir la valeur stockée dans un index, sélectionné au hasard, dans la tranche.

16
ANisus

Obtenir une clé aléatoire à partir d'une carte implique simplement un deuxième compteur comme un nombre aléatoire.

// choices = map[string]...

i := Rand.Intn(len(choices))
var k string
for k = range choices {
  if i == 0 {
    break
  }
  i--
}

fmt.Println(k, choices[k])

La carte peut avoir n'importe quel type de clé valide et il vous suffit de modifier var k string correspondre. Vous pouvez regrouper cela en fonction:

func randIntMapKey(m map[int]string) int {
    i := Rand.Intn(len(m))
    for k := range m {
        if i == 0 {
            return k
        }
        i--
    }
    panic("never")
}
7
Xeoncross

Voici une version plus générique, bien qu'elle puisse être moins efficace:

    keys := reflect.ValueOf(mapI).MapKeys()
    return keys[Rand.Intn(len(keys))].Interface()

https://play.golang.org/p/0uvpJ0Dig4e

5
Briank