Come verificare se una mappa contiene una chiave in Go?


Risposte:


1475

Una riga di risposta:

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

Spiegazione:

ifle istruzioni in Go possono includere sia una condizione che un'istruzione di inizializzazione. L'esempio sopra usa entrambi:

  • inizializza due variabili: valriceverà il valore di "pippo" dalla mappa o un "valore zero" (in questo caso la stringa vuota) e okriceverà un valore bool che verrà impostato truese "pippo" fosse effettivamente presente nella mappa

  • valuta ok, che sarà truese "pippo" era nella mappa

Se "pippo" è effettivamente presente nella mappa, il corpo ifdell'istruzione verrà eseguito e valsarà locale a tale scopo.


2
Questo può essere meglio spiegato come funziona (come l'altro commento di peterSO)
Chmouel Boudjnah,

6
@Kiril var val string = ""rimarrà lo stesso, val, ok :=crea una nuova variabile locale con lo stesso nome visibile solo in quel blocco.
OneOfOne,

1
ottima risposta, diresti che la complessità di questo è O (1) ??
Mheni,

1
@Mheni, so che sono un po 'in ritardo qui, ma questa domanda discute la complessità della ricerca in corso. Il più delle volte la complessità ammortizzata è O (1) ma vale la pena leggere le risposte su quella domanda.
3ocene,

70
Una sintassi così confusa rispetto a quella di Python if key in dict.
Pranjal Mittal,

131

Oltre a The Go Programming Language Specification , dovresti leggere Effective Go . Nella sezione sulle mappe , dicono, tra le altre cose:

Un tentativo di recuperare un valore della mappa con una chiave non presente nella mappa restituirà il valore zero per il tipo di voci nella mappa. Ad esempio, se la mappa contiene numeri interi, la ricerca di una chiave inesistente restituirà 0. Un set può essere implementato come una mappa con valore bool. Impostare la voce della mappa su true per inserire il valore nel set, quindi testarlo mediante una semplice indicizzazione.

attended := map[string]bool{
    "Ann": true,
    "Joe": true,
    ...
}

if attended[person] { // will be false if person is not in the map
    fmt.Println(person, "was at the meeting")
}

A volte è necessario distinguere una voce mancante da un valore zero. C'è una voce per "UTC" o è 0 perché non è affatto nella mappa? Puoi discriminare con una forma di assegnazione multipla.

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

Per ovvie ragioni questo è chiamato il linguaggio "virgola ok". In questo esempio, se tz è presente, i secondi verranno impostati in modo appropriato e ok sarà vero; in caso contrario, i secondi verranno impostati su zero e ok sarà falso. Ecco una funzione che lo mette insieme ad un bel rapporto di errore:

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

Per verificare la presenza nella mappa senza preoccuparsi del valore effettivo, è possibile utilizzare l'identificatore vuoto (_) al posto della normale variabile per il valore.

_, present := timeZone[tz]

58

Ho cercato nella mailing list go-nut e trovato una soluzione pubblicata da Peter Froehlich il 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")
        }
}

O, più compatto,

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

Nota, usando questo modulo ifdell'istruzione, le variabili valuee oksono visibili solo all'interno delle ifcondizioni.


21
Se sei davvero interessato a sapere se la chiave esiste o meno e non ti interessa il valore, puoi usarlo _, ok := dict["baz"]; ok. La _parte butta via il valore invece di creare una variabile temporanea.
Matthew Crumley,

26

Risposta breve

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

Esempio

Ecco un esempio nel Go Playground .

Risposta più lunga

Per la sezione Mappe di Effective Go :

Un tentativo di recuperare un valore della mappa con una chiave non presente nella mappa restituirà il valore zero per il tipo di voci nella mappa. Ad esempio, se la mappa contiene numeri interi, la ricerca di una chiave inesistente restituirà 0.

A volte è necessario distinguere una voce mancante da un valore zero. C'è una voce per "UTC" o è quella stringa vuota perché non è affatto nella mappa? Puoi discriminare con una forma di assegnazione multipla.

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

Per ovvie ragioni questo è chiamato il linguaggio "virgola ok". In questo esempio, se tz è presente, i secondi verranno impostati in modo appropriato e ok sarà vero; in caso contrario, i secondi verranno impostati su zero e ok sarà falso. Ecco una funzione che lo mette insieme ad un bel rapporto di errore:

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

Per verificare la presenza nella mappa senza preoccuparsi del valore effettivo, è possibile utilizzare l'identificatore vuoto (_) al posto della normale variabile per il valore.

_, present := timeZone[tz]

13

Come notato da altre risposte, la soluzione generale è utilizzare un'espressione indice in un'assegnazione del modulo speciale:

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

Questo è bello e pulito. Ha alcune restrizioni però: deve essere un incarico di forma speciale. L'espressione sul lato destro deve essere solo l'espressione dell'indice della mappa e l'elenco delle espressioni a sinistra deve contenere esattamente 2 operandi, il primo al quale è assegnabile il tipo di valore e un secondo al quale boolè assegnabile un valore. Il primo valore del risultato di questo modulo speciale sarà il valore associato alla chiave e il secondo valore indicherà se esiste effettivamente una voce nella mappa con la chiave specificata (se la chiave esiste nella mappa). L'elenco delle espressioni sul lato sinistro può contenere anche l' identificatore vuoto se uno dei risultati non è necessario.

È importante sapere che se il valore della mappa indicizzata è nilo non contiene la chiave, l'espressione dell'indice restituisce il valore zero del tipo di valore della mappa. Quindi per esempio:

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

Provalo sul Go Playground .

Quindi, se sappiamo che non utilizziamo il valore zero nella nostra mappa, possiamo trarne vantaggio.

Ad esempio, se il tipo di valore è stringe sappiamo che non memorizziamo mai voci nella mappa in cui il valore è la stringa vuota (valore zero per il stringtipo), possiamo anche verificare se la chiave è nella mappa confrontando il non speciale forma dell'espressione dell'indice (risultato della) al valore zero:

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] != "")

Output (provalo sul Go Playground ):

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

In pratica ci sono molti casi in cui non memorizziamo il valore zero nella mappa, quindi questo può essere usato abbastanza spesso. Ad esempio, le interfacce e i tipi di funzione hanno un valore zero nil, che spesso non memorizziamo nelle mappe. Quindi testare se una chiave è nella mappa può essere raggiunto confrontandolo con nil.

L'uso di questa "tecnica" ha anche un altro vantaggio: è possibile verificare l'esistenza di più chiavi in ​​modo compatto (non è possibile farlo con lo speciale modulo "virgola ok"). Altre informazioni al riguardo: controlla se esiste la chiave in più mappe in una condizione

Ottenere il valore zero del tipo di valore durante l'indicizzazione con una chiave inesistente ci consente anche di utilizzare le mappe con boolvalori comodamente come set . Per esempio:

set := map[string]bool{
    "one": true,
    "two": true,
}

fmt.Println("Contains 'one':", set["one"])

if set["two"] {
    fmt.Println("'two' is in the set")
}
if !set["three"] {
    fmt.Println("'three' is not in the set")
}

Emette (provalo sul Go Playground ):

Contains 'one': true
'two' is in the set
'three' is not in the set

Vedi correlati: Come posso creare un array che contiene stringhe uniche?


1
cosa c'è Tdentro var v, ok T = a[x]? non okdeve essere bool?
Kokizzu,

2
@Kokizzu Questa è la forma generale della dichiarazione variabile. Inizialmente potremmo pensare che funzionerebbe (compilare) solo se la mappa fosse di tipo map[bool]booled Tè bool, ma funziona anche se la mappa è di tipo map[interface{}]booled Tè interface{}; inoltre funziona anche con tipi personalizzati che hanno boolcome tipo sottostante, vedi tutto su Playground . Quindi, poiché tale modulo è valido con più tipi sostituitiT , ecco perché Tviene utilizzato il generale . Il tipo di okpuò essere qualsiasi cosa a cui può essere assegnato un non tipizzatobool .
Icza,


4
    var d map[string]string
    value, ok := d["key"]
    if ok {
        fmt.Println("Key Present ", value)
    } else {
        fmt.Println(" Key Not Present ")
    }

3
    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)

Quindi, vai a eseguire maps.go esiste qualcosa di simile? vero non esiste? falso



Grazie per il contributo, ma penso che le risposte attuali coprano bene la domanda. Da quello che stai dicendo qui la tua risposta si adatterebbe meglio a un modo migliore di implementare set nel tipo di domanda Go .
Tomasz,

_, ok = m["somestring"]dovrebbe essere=_, ok := m["somestring"]
Elroy Jetson il

3

È menzionato sotto "Espressioni dell'indice" .

Un'espressione indice su una mappa a di tipo map [K] V utilizzata in un'assegnazione o inizializzazione del modulo speciale

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

produce un valore booleano aggiuntivo non tipizzato. Il valore di ok è vero se la chiave x è presente nella mappa e false in caso contrario.


1

A questo scopo è possibile utilizzare un'assegnazione a due valori. Si prega di controllare il mio programma di esempio di seguito

package main

import (
    "fmt"
)

func main() {
    //creating a map with 3 key-value pairs
    sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
    //A two value assignment can be used to check existence of a key.
    value, isKeyPresent := sampleMap["key2"]
    //isKeyPresent will be true if key present in sampleMap
    if isKeyPresent {
        //key exist
        fmt.Println("key present, value =  ", value)
    } else {
        //key does not exist
        fmt.Println("key does not exist")
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.