Sé que puedo iterar sobre un mapa m
,
for k, v := range m { ... }
y busque una clave, pero ¿hay una manera más eficiente de probar la existencia de una clave en un mapa?
No pude encontrar la respuesta en las especificaciones del idioma .
Sé que puedo iterar sobre un mapa m
,
for k, v := range m { ... }
y busque una clave, pero ¿hay una manera más eficiente de probar la existencia de una clave en un mapa?
No pude encontrar la respuesta en las especificaciones del idioma .
Respuestas:
Respuesta de una línea:
if val, ok := dict["foo"]; ok {
//do something here
}
if
Las declaraciones en Go pueden incluir tanto una condición como una declaración de inicialización. El ejemplo anterior usa ambos:
inicializa dos variables: val
recibirá el valor de "foo" del mapa o un "valor cero" (en este caso, la cadena vacía) y ok
recibirá un bool que se establecerá true
si "foo" estaba realmente presente en el mapa
evalúa ok
, que será true
si "foo" estaba en el mapa
Si "foo" está realmente presente en el mapa, el cuerpo de la if
declaración se ejecutará y val
será local en ese ámbito.
var val string = ""
seguirá siendo el mismo, val, ok :=
crea una nueva variable local con el mismo nombre que solo es visible en ese bloque.
if key in dict
.
Además de la especificación del lenguaje de programación The Go , debe leer Effective Go . En la sección de mapas , dicen, entre otras cosas:
Un intento de obtener un valor de mapa con una clave que no está presente en el mapa devolverá el valor cero para el tipo de las entradas en el mapa. Por ejemplo, si el mapa contiene números enteros, buscar una clave inexistente devolverá 0. Un conjunto puede implementarse como un mapa con valor tipo bool. Establezca la entrada del mapa en true para poner el valor en el conjunto y luego pruébelo mediante una indexación simple.
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") }
Algunas veces necesita distinguir una entrada faltante de un valor cero. ¿Hay una entrada para "UTC" o es 0 porque no está en el mapa? Puede discriminar con una forma de asignación múltiple.
var seconds int var ok bool seconds, ok = timeZone[tz]
Por razones obvias, esto se llama modismo de "coma ok". En este ejemplo, si tz está presente, los segundos se establecerán adecuadamente y ok será verdadero; si no, los segundos se pondrán a cero y ok será falso. Aquí hay una función que lo combina con un buen informe de error:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Para comprobar la presencia en el mapa sin preocuparse por el valor real, puede usar el identificador en blanco (_) en lugar de la variable habitual para el valor.
_, present := timeZone[tz]
Busqué en la lista de correos electrónicos y encontré una solución publicada por Peter Froehlich el 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, más compactamente,
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
Tenga en cuenta que, utilizando esta forma de la if
declaración, las variables value
y ok
solo son visibles dentro de las if
condiciones.
_, ok := dict["baz"]; ok
. La _
parte arroja el valor en lugar de crear una variable temporal.
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
Aquí hay un ejemplo en Go Playground .
Según la sección de Mapas de Effective Go :
Un intento de obtener un valor de mapa con una clave que no está presente en el mapa devolverá el valor cero para el tipo de las entradas en el mapa. Por ejemplo, si el mapa contiene enteros, buscar una clave inexistente devolverá 0.
Algunas veces necesita distinguir una entrada faltante de un valor cero. ¿Hay una entrada para "UTC" o es la cadena vacía porque no está en el mapa? Puede discriminar con una forma de asignación múltiple.
var seconds int var ok bool seconds, ok = timeZone[tz]
Por razones obvias, esto se llama modismo de "coma ok". En este ejemplo, si tz está presente, los segundos se establecerán adecuadamente y ok será verdadero; si no, los segundos se pondrán a cero y ok será falso. Aquí hay una función que lo combina con un buen informe de error:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Para comprobar la presencia en el mapa sin preocuparse por el valor real, puede usar el identificador en blanco (_) en lugar de la variable habitual para el valor.
_, present := timeZone[tz]
Como se señaló en otras respuestas, la solución general es usar una expresión de índice en una asignación de la forma especial:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
Esto es lindo y limpio. Sin embargo, tiene algunas restricciones: debe ser una asignación de forma especial. La expresión del lado derecho debe ser solo la expresión del índice del mapa, y la lista de expresiones del lado izquierdo debe contener exactamente 2 operandos, el primero al que se puede asignar el tipo de valor y el segundo al que bool
se puede asignar un valor. El primer valor del resultado de esta forma especial será el valor asociado con la clave, y el segundo valor indicará si realmente hay una entrada en el mapa con la clave dada (si la clave existe en el mapa). La lista de expresiones del lado izquierdo también puede contener el identificador en blanco si uno de los resultados no es necesario.
Es importante saber que si el valor del mapa indexado es nil
o no contiene la clave, la expresión del índice se evalúa como el valor cero del tipo de valor del mapa. Así por ejemplo:
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
Pruébalo en Go Playground .
Entonces, si sabemos que no usamos el valor cero en nuestro mapa, podemos aprovechar esto.
Por ejemplo, si el tipo de valor es string
, y sabemos que nunca almacenamos entradas en el mapa donde el valor es la cadena vacía (valor cero para el string
tipo), también podemos probar si la clave está en el mapa comparando los valores no especiales forma de (resultado de) la expresión de índice al valor cero:
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] != "")
Salida (pruébalo en Go Playground ):
Key 0 exists: true
Key 1 exists: true
Key 2 exists: false
En la práctica, hay muchos casos en los que no almacenamos el valor de valor cero en el mapa, por lo que puede usarse con bastante frecuencia. Por ejemplo, las interfaces y los tipos de función tienen un valor cero nil
, que a menudo no almacenamos en los mapas. Por lo tanto, se puede probar si una clave está en el mapa comparándola con nil
.
El uso de esta "técnica" también tiene otra ventaja: puede verificar la existencia de varias claves de manera compacta (no puede hacerlo con el formulario especial "coma ok"). Más sobre esto: compruebe si la clave existe en varios mapas en una condición
Obtener el valor cero del tipo de valor cuando se indexa con una clave no existente también nos permite usar mapas con bool
valores convenientemente como conjuntos . Por ejemplo:
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")
}
Sale (pruébalo en Go Playground ):
Contains 'one': true
'two' is in the set
'three' is not in the set
Ver relacionado: ¿Cómo puedo crear una matriz que contenga cadenas únicas?
T
en var v, ok T = a[x]
? no ok
debe ser bool?
map[bool]bool
y T
es bool
, pero también funciona si el mapa es de tipo map[interface{}]bool
y T
es interface{}
; Además, también funciona con tipos personalizados que tienen bool
como tipo subyacente, ver todo en Go Playground . Entonces, dado que esa forma es válida con múltiples tipos sustituidos T
, es por eso que T
se usa el general . Tipo de ok
puede ser cualquier cosa a la que se le pueda asignar un sin tipobool
.
mejor manera aquí
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)
Luego, ve a ejecutar maps.go somestring existe? verdad no existe? falso
_, ok = m["somestring"]
debería ser=_, ok := m["somestring"]
Se menciona en "Expresiones de índice" .
Una expresión de índice en un mapa a de tipo mapa [K] V usado en una asignación o inicialización de la forma especial
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
produce un valor booleano sin tipo adicional. El valor de ok es verdadero si la clave x está presente en el mapa, y falso en caso contrario.
Se puede usar una asignación de dos valores para este propósito. Por favor revise mi programa de muestra a continuación
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")
}
}