Question Comment vérifier si une carte contient une clé?


Je sais que je peux parcourir une carte par,

for k, v := range m { ... }

et recherchez une clé, mais existe-t-il un moyen plus efficace de tester l’existence d’une clé dans une carte? Merci. Je n'ai pas trouvé de réponse dans le Spécification de langue.


440
2018-01-12 16:18


origine


Réponses:


Une réponse en ligne:

if val, ok := dict["foo"]; ok {
    //do something here
}

Explication:

if Les instructions dans Go peuvent inclure à la fois une condition et une instruction d'initialisation. L'exemple ci-dessus utilise les deux:

  • initialise deux variables - val recevra soit la valeur de "foo" de la carte ou une "valeur zéro" (dans ce cas, la chaîne vide) et ok recevra un bool qui sera mis à true si "foo" était présent sur la carte

  • évalue ok, qui sera true si "foo" était sur la carte

Si "foo" est effectivement présent sur la carte, le corps de la if déclaration sera exécuté et val sera locale à cette portée.


831
2018-01-12 16:48



Modifier: La réponse suivante est antérieure à Go 1. À partir de Go 1, il n'est plus exact / valide.


En plus de La spécification du langage de programmation Govous devriez lire Go efficace. Dans la section sur Plansils disent entre autres:

"Une tentative d'extraction d'une valeur de carte avec une clé qui n'est pas présente dans la carte provoquera le blocage du programme, mais il existe un moyen de le faire en toute sécurité en utilisant une assignation multiple."

var seconds int
var ok bool
seconds, ok = timeZone[tz]

"Pour tester la présence sur la carte sans vous soucier de la valeur réelle, vous pouvez utiliser l'identificateur vide, un trait de soulignement simple (_) .L'identifiant vide peut être assigné ou déclaré avec n'importe quelle valeur, avec la valeur rejetée sans danger. Pour tester la présence dans une carte, utilisez l'identificateur vide à la place de la variable habituelle pour la valeur. "

_, present := timeZone[tz]

87
2018-01-12 17:37



Recherché sur le liste de courriel et a trouvé une solution publiée par Peter Froehlich le 15/11/2009.

package main

import "fmt"

func main() {
        dict := map[string]int {"foo" : 1, "bar" : 2}
        value, ok := dict["baz"]
        if ok {
                fmt.Println("value: ", value)
        } else {
                fmt.Println("key not found")
        }
}

Ou, plus compactement,

if value, ok := dict["baz"]; ok {
    fmt.Println("value: ", value)
} else {
    fmt.Println("key not found")
}

Notez, en utilisant cette forme de if déclaration, le value et ok les variables ne sont visibles qu'à l'intérieur du if conditions.


36
2018-01-12 16:40



Réponse courte

_, exists := timeZone[tz]    // Just checks for key existence
val, exists := timeZone[tz]  // Checks for key existence and retrieves the value

Exemple

Voici un exemple au terrain de jeu de go.

Réponse plus longue

Par le Plans section de Go efficace:

Une tentative d'extraction d'une valeur de carte avec une clé qui n'est pas présente dans la carte renverra la valeur zéro pour le type des entrées dans la carte. Par exemple, si la carte contient des entiers, rechercher une clé inexistante renverra 0.

Parfois, vous devez distinguer une entrée manquante d'une valeur nulle. Existe-t-il une entrée pour "UTC" ou est-ce la chaîne vide car elle n'est pas dans la carte du tout? Vous pouvez discriminer avec une forme d'assignation multiple.

var seconds int
var ok bool
seconds, ok = timeZone[tz]

Pour des raisons évidentes, cela s'appelle l'idiome "comma ok". Dans cet exemple, si tz est présent, les secondes seront définies correctement et ok sera vrai; sinon, les secondes seront mises à zéro et ok sera faux. Voici une fonction qui le combine avec un bon rapport d'erreur:

func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}

Pour tester la présence sur la carte sans vous soucier de la valeur réelle, vous pouvez utiliser l'identificateur vide (_) à la place de la variable habituelle pour la valeur.

_, present := timeZone[tz]

14
2017-11-09 21:38



Comme noté par d'autres réponses, la solution générale consiste à utiliser un expression d'index dans un affectation de la forme spéciale:

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

C'est sympa et propre. Il y a cependant quelques restrictions: il doit s'agir d'une cession de forme spéciale. L'expression de droite doit être l'expression de l'index de carte uniquement, et la liste d'expressions de gauche doit contenir exactement 2 opérandes, le premier auquel le type de valeur est assignable, et le second auquel un bool la valeur est assignable. La première valeur du résultat de cette expression d'index de forme spéciale sera la valeur associée à la clé, et la deuxième valeur indiquera s'il y a réellement une entrée dans la carte avec la clé donnée (si la clé existe dans la carte). La liste d’expressions de gauche peut également contenir le identifiant vierge si l'un des résultats n'est pas nécessaire.

Il est important de savoir que si la valeur de la carte indexée est nil ou ne contient pas la clé, l'expression de l'index est évaluée à la valeur zéro du type de valeur de la carte. Donc par exemple:

m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0

fmt.Printf("%q %f", s, f) // Prints: "" 0.000000

Essayez le Aller aire de jeux.

Donc, si nous savons que nous n'utilisons pas la valeur zéro sur notre carte, nous pouvons en profiter.

Par exemple si le type de valeur est string, et nous savons que nous ne stockons jamais les entrées dans la carte où la valeur est la chaîne vide (valeur zéro pour le string type), nous pouvons également tester si la clé est dans la carte en comparant la forme non-spécifique de l'expression (résultat de l'index) à la valeur zéro:

m := map[int]string{
    0: "zero",
    1: "one",
}

fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t",
    m[0] != "", m[1] != "", m[2] != "")

Sortie (l'essayer sur le Aller aire de jeux):

Key 0 exists: true
Key 1 exists: true
Key 2 exists: false

En pratique, il y a beaucoup de cas où nous ne stockons pas la valeur zéro dans la carte, donc cela peut être utilisé assez souvent. Par exemple, les interfaces et les types de fonctions ont une valeur nulle nil, que nous ne stockons souvent pas dans les cartes. Donc, tester si une clé est dans la carte peut être réalisé en le comparant à nil.

L'utilisation de cette "technique" a aussi un autre avantage: vous pouvez vérifier l'existence de plusieurs clés de manière compacte (vous ne pouvez pas le faire avec le formulaire spécial "virgule ok"). Plus à ce sujet: Vérifier si la clé existe dans plusieurs cartes en une seule condition


5
2018-04-07 08:05



meilleure façon ici

if _, ok := dict["foo"]; ok {
    //do something here
}

4
2017-10-18 05:17



    var empty struct{}
    var ok bool
    var m map[string]struct{}
    m = make(map[string]struct{})
    m["somestring"] = empty


    _, ok = m["somestring"]
    fmt.Println("somestring exists?", ok) 
    _, ok = m["not"]
    fmt.Println("not exists?", ok)

Ensuite, lancez maps.go SomString existe? vrai n'existe pas? faux


2
2017-07-22 12:19



Il est mentionné sous "Expressions d'index".

Une expression d'index sur une carte de type map [K] V utilisée dans une affectation   ou initialisation de la forme spéciale

v, ok = a[x] 
v, ok := a[x] 
var v, ok = a[x]

donne une valeur booléenne non typée supplémentaire. La valeur de ok est vraie si   la clé x est présente dans la carte et false sinon.


1
2018-06-13 18:54



Juste utiliser

if len(m) == 0 {
    ...
}

-13
2017-09-02 04:39