¿Cómo comprobar si un mapa contiene una llave en go?


Sé que puedo iterar sobre un mapa m por,

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

Y buscar una clave, pero ¿hay una forma más eficiente de probar la existencia de una clave en un mapa? Gracias. No pude encontrar una respuesta en la especificación de lenguaje .

 464
Author: Pablo Jomer, 2010-01-12

10 answers

Respuesta de una línea:

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

Explicación:

if las instrucciones en Go pueden incluir tanto una condición como una instrucció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á en true si "foo" estaba realmente presente en el mapa

  • Evalúa ok, que será true si "foo" estaba en el mapa

Si "foo" está efectivamente presente en el mapa, el cuerpo de la instrucción if se ejecutará y val será local a ese ámbito.

 881
Author: marketer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-20 07:18:01

Editar: La siguiente respuesta es anterior a Go 1. A partir de Go 1, ya no es preciso / válido.


Además de La Especificación del Lenguaje de Programación Go, debe leer Go Efectivo. 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 causará que el programa se bloquee, pero hay una manera de hacerlo de forma segura utilizando un asignación."

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

"Para probar la presencia en el mapa sin preocuparse por el valor real, puede usar el identificador en blanco, un simple subrayado (_). El identificador en blanco se puede asignar o declarar con cualquier valor de cualquier tipo, y el valor se descarta sin causar daño. Para probar la presencia en un mapa, utilice el identificador en blanco en lugar de la variable habitual para el valor."

_, present := timeZone[tz]
 89
Author: peterSO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-06 07:06:12

Buscó en la lista de correo electrónico go-nuts 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 compacto,

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

Nota, usando esta forma de la instrucción if, las variables value y ok solo son visibles dentro de las condiciones if.

 38
Author: grokus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-12 19:01:37

Respuesta corta

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

Ejemplo

Aquí hay un ejemplo en el Go Playground.

Respuesta más larga

Por la sección Mapas de Go efectivo :

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.

A Veces es necesario distingue una entrada que falta 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 el modismo "coma ok". En este ejemplo, si tz está presente, los segundos se configurarán apropiadamente y ok será true; si no, los segundos se configurarán a cero y ok será false. Aquí hay una función que lo pone junto con un buen error informe:

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

Para probar 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]
 15
Author: Matthew Rankin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-09 21:38:00

Como se observa 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 agradable 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 de mapa, y la lista de expresiones del lado izquierdo debe contener exactamente 2 operandos, primero a los que se puede asignar el tipo de valor, y un segundo al que se puede asignar un valor bool. El primer valor del resultado de esta expresión especial de índice de forma será el valor asociado con la clave, y el segundo valor dirá 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 index se evalúa a la 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 el Go Playground.

Así que 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 tipo string), también podemos probar si la clave está en el mapa comparando la forma no especial del (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ébelo en el 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 se puede usar con bastante frecuencia. Por ejemplo, las interfaces y los tipos de funciones tienen un valor cero nil, que a menudo no almacenamos en los mapas. Por lo tanto, probar si una clave está en el mapa se puede lograr comparándola con nil.

Usar esta "técnica" también tiene otra ventaja: puede verificar la existencia de múltiples claves de una 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

 6
Author: icza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:50

Mejor camino aquí

if _, ok := dict["foo"]; ok {
    //do something here
}
 4
Author: Amazingandyyy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-18 05:17:21

Se menciona en "Expresiones de índice".

Una expresión de índice en un mapa a de tipo map [K]V utilizada 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 adicional sin tipo. El valor de ok es verdadero si la tecla x está presente en el mapa, y false de lo contrario.

 3
Author: mroman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-13 18:54:48
    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 mapas.Ve somestring existe? verdadero no existe? false

 2
Author: Lady_Exotel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-22 12:19:35

Se puede usar una asignación de dos valores para este propósito. Por favor, compruebe 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")
    }
}
 0
Author: Fathah Rehman P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-21 10:27:31

Solo use

if len(m) == 0 {
    ...
}
 -13
Author: hacky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-02 05:10:15