So di poter scorrere su una mappa m
di,
for k, v := range m { ... }
e cercare una chiave ma esiste un modo più efficiente di testare l'esistenza di una chiave in una mappa?
Non sono riuscito a trovare la risposta nelle specifiche della lingua .
So di poter scorrere su una mappa m
di,
for k, v := range m { ... }
e cercare una chiave ma esiste un modo più efficiente di testare l'esistenza di una chiave in una mappa?
Non sono riuscito a trovare la risposta nelle specifiche della lingua .
Risposte:
Una riga di risposta:
if val, ok := dict["foo"]; ok {
//do something here
}
if
le istruzioni in Go possono includere sia una condizione che un'istruzione di inizializzazione. L'esempio sopra usa entrambi:
inizializza due variabili: val
riceverà il valore di "pippo" dalla mappa o un "valore zero" (in questo caso la stringa vuota) e ok
riceverà un valore bool che verrà impostato true
se "pippo" fosse effettivamente presente nella mappa
valuta ok
, che sarà true
se "pippo" era nella mappa
Se "pippo" è effettivamente presente nella mappa, il corpo if
dell'istruzione verrà eseguito e val
sarà locale a tale scopo.
var val string = ""
rimarrà lo stesso, val, ok :=
crea una nuova variabile locale con lo stesso nome visibile solo in quel blocco.
if key in dict
.
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]
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 if
dell'istruzione, le variabili value
e ok
sono visibili solo all'interno delle if
condizioni.
_, ok := dict["baz"]; ok
. La _
parte butta via il valore invece di creare una variabile temporanea.
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
Ecco un esempio nel Go Playground .
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]
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 è nil
o 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 è string
e sappiamo che non memorizziamo mai voci nella mappa in cui il valore è la stringa vuota (valore zero per il string
tipo), 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 bool
valori 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?
T
dentro var v, ok T = a[x]
? non ok
deve essere bool?
map[bool]bool
ed T
è bool
, ma funziona anche se la mappa è di tipo map[interface{}]bool
ed T
è interface{}
; inoltre funziona anche con tipi personalizzati che hanno bool
come tipo sottostante, vedi tutto su Playground . Quindi, poiché tale modulo è valido con più tipi sostituitiT
, ecco perché T
viene utilizzato il generale . Il tipo di ok
può essere qualsiasi cosa a cui può essere assegnato un non tipizzatobool
.
modo migliore qui
if _, ok := dict["foo"]; ok {
//do something here
}
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
_, ok = m["somestring"]
dovrebbe essere=_, ok := m["somestring"]
È 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.
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")
}
}